home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / stnvjw20.zip / SETENV.ASM < prev    next >
Assembly Source File  |  1992-10-25  |  68KB  |  3,217 lines

  1. title Set Environment Variable Program.
  2. page 60,120            ; page length = 60
  3.                 ; page width  = 120
  4. ;
  5. ;    This program places a variable in the environment.
  6. ;
  7. ;    SETENV : Copyright (c) 1988 to 1992 by John Wolchak.  
  8. ;      I give permission to alter the code, but not to copy 
  9. ;      or redistribute the altered code without my explicit 
  10. ;      permission.  If you alter the code, please document 
  11. ;      changes and send me a copy, so all can have it.  The 
  12. ;      file Setenv.Doc must always accompany the SETENV 
  13. ;      program when a copy is made for another machine.  
  14. ;      This code, to the best of my knowledge works well.  
  15. ;      I disclaim any responsibility for the codes actions 
  16. ;      (use at your own risk).  
  17. ;
  18. ;    John Wolchak.
  19. ;    56 Physics Building
  20. ;    University of Saskatchewan.
  21. ;    Saskatoon, Saskatchewan
  22. ;    Canada     S7K 0W0
  23. ;    Phone: (306) 966-4852
  24. ;    Inter_Network: Wolchak@Admin.Usask.Ca
  25. ;
  26. ;    To assemble:
  27. ;    masm setenv,,,
  28. ;    link setenv,,,
  29. ;    exe2bin setenv.exe setenv.com
  30. ;    delete setenv.obj
  31. ;    delete setenv.exe
  32. ;
  33. code segment
  34. assume cs:code,ds:code
  35. org 100h
  36.  
  37. start:        jmp beginning
  38. ;
  39. ;        Data Area
  40. ;
  41. exit_code    db    03h        ; Environment variable created.
  42.                     ; PSP is Program Segment Prefix.
  43. cpsp        dw    00h        ; The psp of command.com.
  44. env_off        dw    00h        ; Environment offset address.
  45. env_siz        dw    00h        ; Environment size in bytes.
  46. dos_maj        db    00h        ; DOS major version.
  47. dos_min        db    00h        ; DOS minor version.
  48. set        db    "set "
  49. s_rce        dw    03h        ; Size of Root Comm Env.
  50. l_rce        db    "rce"
  51. u_rce        db    "RCE"
  52. v_rce        dw    00h        ; RCE value.
  53. a_rce        dw    00h        ; Segment address.
  54. ;d_rce        db    0ffh dup(0)    ; Data string of Set command.
  55. s_data        dw    00h        ; Size of environment data.
  56. a_env_var    dw    00h        ; Address of environment variable.
  57. s_env_var    dw    00h        ; Environment variable size.
  58. ;d_env_var    db    0ffh dup(0)    ; Environment data.
  59. ;null        db    00h,00h        ; Environment tail.
  60. y_prompt    dw    08h        ; Size of '%prompt '.
  61. x_prompt    dw    06h        ; Size.
  62. l_prompt    db    "prompt"
  63. u_prompt    db    "PROMPT"
  64. o_prompt    dw    00h        ; Offset of prompt.
  65. s_def        dw    03h        ; Size of default.
  66. l_def        db    "def"
  67. u_def        db    "DEF"
  68. x_def        dw    00h        ; Default value size.
  69. ;v_def        dw    100 dup(0)    ; Default value.
  70. s_echo        dw    06h        ; Size of echo.
  71. l_echo        db    "noecho"
  72. u_echo        db    "NOECHO"
  73. v_echo        dw    00h        ; Echo on.
  74. s_upper        dw    05h        ; Size of upper.
  75. l_upper        db    "upper"
  76. u_upper        db    "UPPER"
  77. v_upper        dw    00h        ; Upper case on.
  78. s_lower        dw    05h        ; Size of lower.
  79. l_lower        db    "lower"
  80. u_lower        db    "LOWER"
  81. v_lower        dw    00h        ; Lower case on.
  82. s_trim        dw    04h        ; Size of trim.
  83. l_trim        db    "trim"
  84. u_trim        db    "TRIM"
  85. v_trim        dw    00h        ; Trim leading spaces.
  86. w_trim        dw    00h        ; Trim trailing spaces.
  87. o_tmp        dw    00h        ; Save temporary address.
  88. s_timo        dw    05h        ; Size of timo.
  89. l_timo        db    "timo="
  90. u_timo        db    "TIMO="
  91. v_timo        dw    00h        ; Time out infinit.
  92. c_brk        db    00h        ; Control break status.
  93. d_ent        db    00h        ; Entry days.
  94. h_ent        db    00h        ; Entry hours.
  95. m_ent        db    00h        ; Entry minutes.
  96. s_ent        db    00h        ; Entry seconds.
  97. d_stt        db    00h        ; Stop time day.
  98. h_stt        db    00h        ; Stop time hours.
  99. m_stt        db    00h        ; Stop time minutes.
  100. s_stt        db    00h        ; Stop time seconds.
  101. f_stt        db    00h        ; Stop flag exit type.
  102. s_rep        dw    03h        ; Size of replace.
  103. l_rep        db    "rep"
  104. u_rep        db    "REP"
  105. v_rep        dw    00h
  106. s_arg1        dw    00h        ; Replace old value size.
  107. ;d_arg1        dw    100 dup(0)    ; Replace old value.
  108. s_arg2        dw    00h        ; Replace new value size.
  109. ;d_arg2        dw    100 dup(0)    ; Replace new value.
  110. s_chr        dw    03h        ; Size of chr.
  111. l_chr        db    "chr"
  112. u_chr        db    "CHR"
  113. n_chr        dw    00h        ; Decimal value character.
  114. s_elem        dw    04h        ; Size of element.
  115. l_elem        db    "elem"
  116. u_elem        db    "ELEM"
  117. c_elem        db    00h        ; Element delimiter
  118. e_elem        dw    00h        ; Element number.
  119. s_mid        dw    03h        ; Size of mid.
  120. l_mid        db    "mid"
  121. u_mid        db    "MID"
  122. y_mid        dw    00h        ; Substr starting position.
  123. z_mid        dw    00h        ; Substr length.
  124. b_env        dw    00h        ; Program env address.
  125. o_env        dw    00h        ; Variable offset.
  126. f_env        db    00h        ; Variable search.
  127. s_env        dw    00h        ; Variable name size.
  128. n_env        dw    20 dup(0)    ; Variable name.
  129. w_mid        dw    00h        ; Variable name size.
  130. x_mid        dw    20 dup(0)    ; Variable name.
  131. s_loc        dw    03h        ; Size of loc.
  132. l_loc        db    "loc"
  133. u_loc        db    "LOC"
  134. e_loc        dw    00h        ; Locate starting position.
  135. s_len        dw    03h        ; Size of len.
  136. l_len        db    "len"
  137. u_len        db    "LEN"
  138. s_sum        dw    03h        ; Size of sum.
  139. l_sum        db    "sum"
  140. u_sum        db    "SUM"
  141. v_sum        dw    00h
  142. f_sum        db    "+"        ; Add or subtract flag.
  143. nmb_sgn        db    "+"        ; Sign for number.
  144. nmb_tst        db    00h        ; Test for sign.
  145. dec_zfl        db    00h        ; Decimal zero flag.
  146. l_eq        dw    "eq"
  147. u_eq        dw    "EQ"
  148. l_lt        dw    "lt"
  149. u_lt        dw    "LT"
  150. l_le        dw    "le"
  151. u_le        dw    "LE"
  152. l_gt        dw    "gt"
  153. u_gt        dw    "GT"
  154. l_ge        dw    "ge"
  155. u_ge        dw    "GE"
  156. e_oper        db    00h        ; Test for equal.
  157. l_oper        db    00h        ; Test for less than.
  158. g_oper        db    00h        ; Test for greater than
  159. s_chgup        dw    05h        ; Size of Change upper.
  160. l_chgup        db    "chgup"
  161. u_chgup        db    "CHGUP"
  162. v_chgup        dw    00h        ; Change upper flag.
  163. s_chglo        dw    05h        ; Size of Change lower.
  164. l_chglo        db    "chglo"
  165. u_chglo        db    "CHGLO"
  166. v_chglo        dw    00h        ; Change lower flag.
  167. s_dosv        dw    04h        ; Size of Dos Major.
  168. l_dosv        db    "dosv"
  169. u_dosv        db    "DOSV"
  170. s_dosm        dw    04h        ; Size of Dos Minor.
  171. l_dosm        db    "dosm"
  172. u_dosm        db    "DOSM"
  173. s_cwd        dw    03h        ; Size of Current directory.
  174. l_cwd        db    "cwd"
  175. u_cwd        db    "CWD"
  176. ;d_cwd        db    0ffh dup(0)    ; Data area (temporary).
  177. s_cfd        dw    03h        ; Size of Current directory.
  178. l_cfd        db    "cfd"
  179. u_cfd        db    "CFD"
  180. s_time        dw    04h        ; Current time.
  181. l_time        db    "time"
  182. u_time        db    "TIME"
  183. s_date        dw    04h        ; Current date.
  184. l_date        db    "date"
  185. u_date        db    "DATE"
  186. z_date        db    "1"        ; Date format.
  187. s_drive        dw    05h        ; Size of drive.
  188. l_drive        db    "drive"
  189. u_drive        db    "DRIVE"
  190. s_path        dw    05h        ; Size of Path.
  191. d_path        db    "PATH="
  192. s_comspec    dw    08h        ; Size of Comspec.
  193. d_comspec    db    "COMSPEC="
  194. s_prompt    dw    07h        ; Size of Prompt=.
  195. d_prompt    db    "PROMPT="
  196. s_setenv    dw    07h        ; Size of Setenv=.
  197. d_setenv    db    "SETENV="
  198. author        db    "Set Environment Variable Program V2.0 (c) 25-Oct-1992 "
  199.         db    "by John Wolchak.",13,10
  200. d_cwd        db    "Usage is:  SETENV <variable> <value>  "
  201.         db    "or  SETENV %rce <variable> <value>",13,10,9
  202.         db    "<variable> by it's self to erase variable.",13,10,9
  203.         db    "<value> can be: '%rep<del><txt1><del><txt2><del>' "
  204.         db    "text replace.",13,10,9
  205.         db    "  '%chgup' or 'chglo' upper/lower case environment "
  206.         db    "variable data.",13,10,9
  207.         db    "  '%prompt %noecho %upper "
  208. d_rce        db    "%def<del><text><del> <message>'.",13,10,9
  209.         db    "     '%noecho' for no echo, '%upper' '%lower' "
  210.         db    "upper/lower case only.",13,10,9
  211.         db    "     '%def<del><text><del>' supply a default,"
  212.         db    " '%trim' trim spaces.",13,10,9
  213.         db    "     '%timo=hh:mm:ss' prompt time out, time length."
  214.         db    13,10,9
  215.         db    "<value> can include keys such as:   "
  216.         db    "ie  setenv drivedir %drive:%cwd",13,10,9
  217. d_arg1        db    "  %dosv / %dosm for DOS major / minor version."
  218.         db    13,10,9
  219.         db    "  %cwd or %cfd for current directory, "
  220.         db    "  %drive for drive letter.",13,10,9
  221.         db    "  %time / %daten for current time / date format 'n'."
  222.         db    13,10,9
  223. v_def        db    "  %+n / %-n for default drive plus / minus 'n'."
  224.         db    13,10,9
  225.         db    "  %loc/<n>/<var>/<str>/  %len/<var>/"
  226.         db    "  %sum/<var>/<n>/",13,10,9
  227.         db    "  %mid/<var>/<n1>/<n2>/  %elem/<n>/<char>/<var>/"
  228.         db    "  %chr/<n>/",13,10
  229. d_arg2        db    "Note:     Use %% to represent a single % in BAT files."
  230.         db    13,10
  231.         db    "       SETENV return codes:",9,9
  232.         db    "no command, help issued     00h",13,10
  233. d_env_var    db    "root environment set        01h",9
  234.         db    "environment variable erased    02h",13,10
  235.         db    "environment variable created    03h",9
  236.         db    "don't know about MS-DOS V1.x    04h",13,10
  237.         db    "environment variable updated    05h",9
  238.         db    "unmatched delimiter        06h",13,10
  239.         db    "not a valid argument        07h",9
  240.         db    "environment variable not found    08h",13,10
  241.         db    "offset drive will be invalid    09h",9
  242.         db    "environment space is full    10h"
  243.         db    "$"
  244. ;
  245. ;    If the help is changed then the variables d_cwd, d_rce
  246. ;        v_def, d_arg1, d_arg2, and d_env_var need to be
  247. ;        changed to  the size of the comments above.
  248. ;        v_def, d_arg1, and d_arg2 are approximately 100
  249. ;        d_cwd, d_rce, and d_env_var are approximately 255
  250. ;        remember the DOS command line is 123 and you can %rep///
  251. ;
  252. ;        Code Area
  253. ;
  254. Beginning:
  255.         mov sp, offset stack    ; Set up local stack.
  256.         mov si, 80h        ; Offset of command line.
  257.         lodsb            ; Get a byte.
  258.         cmp al, 00h        ; Is there any data.
  259.         jnz get_ver        ; Yes. Jump.
  260. dis_help:
  261.         mov dx, offset author    ; Help message.
  262.         mov ah, 09h        ; Display it.
  263.         int 21h
  264.         mov exit_code, 00h    ; No command, help issued.
  265.         jmp nor_term        ; Exit.
  266.  
  267. get_ver:    
  268.         mov ah, 30h        ; Get DOS version number.
  269.         int 21h
  270.  
  271.         mov dos_maj, al
  272.         mov dos_min, ah
  273.  
  274.         cmp ah, 01h
  275.         jnz cont
  276.         mov exit_code, 04h    ; No MS-DOS version 1.x.
  277.         jmp nor_term        ; Exit.
  278.  
  279. ;        Get rid of leading spaces and tabs.
  280. cont:
  281.         lodsb            ; Get a byte.
  282.         cmp al, " "        ; Is it a leading blank.
  283.         jz cont            ; Yes.  Loop.
  284.         cmp al, 09h        ; Is it a leading tab.
  285.         jz cont            ; Yes.  Loop.
  286.         cmp al, "%"        ; Is it a special one.
  287.         jz rce            ; Yes.  Use it.
  288.         cmp al, 0dh        ; Is it a carriage return.
  289.         jz dis_help        ; Yes. dis_help.
  290. cont_on:
  291.         dec si
  292.         jmp var
  293.  
  294. rce:
  295. ;        Handle %rce.
  296.         push si
  297.         mov di, si        ; Set destination.
  298.         mov si, offset l_rce    ; Set source.
  299.         mov cx, s_rce
  300.         rep cmpsb        ; Is it %rce.
  301.         jz set_rce        ; Yes, Jump out.
  302.  
  303.         pop si
  304.         push si
  305.         mov di, si        ; Set destination.
  306.         mov si, offset u_rce    ; Set source.
  307.         mov cx, s_rce
  308.         rep cmpsb        ; Is it %RCE.
  309.         jz set_rce        ; Yes, Jump out.
  310.  
  311.         pop si
  312.         jmp cont_on
  313. set_rce:
  314.         pop si
  315.         inc si
  316.         inc si
  317.         inc si
  318.         mov v_rce, 01h        ; Root Command Environment.
  319.  
  320. ;        Get rid of leading spaces and tabs.
  321. var:
  322.         lodsb            ; Get a byte.
  323.         cmp al, " "        ; Is it a leading blank.
  324.         jz var            ; Yes.  Loop.
  325.         cmp al, 09h        ; Is it a leading tab.
  326.         jz var            ; Yes.  Loop.
  327.  
  328.         dec si            ; Backup for the character.
  329.         mov a_env_var, si    ; Offset of the variable.
  330.         mov di, offset d_env_var ; Offset of env. variable.
  331.  
  332. ;        Get the variable name,
  333. ;        and convert to upper case.
  334. get_var:
  335.         lodsb            ; Get a byte.
  336.         cmp al, " "        ; Is it the end of the variable?
  337.         jz var_end        ; Yes.  Jump out.
  338.         cmp al, 09h        ; Is it the end of the variable?
  339.         jz var_end        ; Yes.  Jump out.
  340.         cmp al, "="        ; Is it the end of the variable?
  341.         jz var_end        ; Yes. Jump out.
  342.         cmp al, 0dh        ; Is it the end.
  343.         jz no_data        ; Yes. We got it.
  344.         cmp al, "z"        ; Is
  345.         jg no_lower        ;   it
  346.         cmp al, "a"        ;     lower
  347.         jb no_lower        ;       case?
  348.         sub al, 20h        ; Make it upper case.
  349. no_lower:
  350.         stosb            ; Save the byte.
  351.         jmp get_var
  352.  
  353. no_data:
  354.         mov al, 0dh
  355.         mov [si], al
  356. var_end:
  357.         mov al, "="        ; Set the end of variable.
  358.         stosb            ; Save it.
  359.         mov -1[si], al        ; And the command line.
  360.  
  361.         mov ax, si        ; Get the offset.
  362.         mov bx, a_env_var    ; Beginning of the variable.
  363.         sub ax, bx        ; Get the variable length.
  364.         mov s_env_var, ax    ; And save it.
  365.  
  366. var_end1:
  367.         lodsb            ; Get a byte.
  368.         cmp al, " "        ; Is it a blank.
  369.         jz var_end1        ; Loop.
  370.         cmp al, 09h        ; Is it a tab.
  371.         jz var_end1        ; Loop.
  372.         dec si
  373.  
  374.         mov al, [si]        ; Get a byte.
  375.         cmp al, "%"        ; Is it a special one.
  376.         jz prompt        ; Yes. Jump out.
  377.  
  378. ;        Get the data part.
  379. get_data:
  380.         mov al, [si]        ; Get a byte.
  381.         cmp al, "%"        ; Is it a special one.
  382.         jz percent_near        ; Yes. Jump out.
  383. get_next:
  384.         lodsb            ; Get a byte.
  385.         cmp al, 0dh        ; Is it the end.
  386.         jz data_end_near    ; Yes. We got it.
  387.         stosb            ; Save the byte.
  388.         jmp get_data
  389.  
  390. data_end_near:
  391.         jmp data_end
  392. percent_near:
  393.         jmp percent
  394.  
  395. ;        Handle %prompt.
  396. prompt:
  397.         mov o_prompt, si
  398.         inc si
  399.         push di
  400.         push si
  401.  
  402.         mov di, si        ; Set destination.
  403.         mov si, offset l_prompt    ; Set Source.
  404.         mov cx, x_prompt
  405.         rep cmpsb        ; Is it %prompt.
  406.         jz sub_fun_near        ; Yes.
  407.  
  408.         pop si
  409.         push si
  410.         mov di, si        ; Set destination.
  411.         mov si, offset u_prompt    ; Set source.
  412.         mov cx, x_prompt
  413.         rep cmpsb        ; Is it %PROMPT.
  414.         jz sub_fun_near        ; Yes.
  415.  
  416. ;        Then check for replace
  417.         jmp replace
  418.  
  419. sub_fun_near:
  420.         jmp sub_fun
  421.  
  422. get_prompt:
  423.         pop si
  424.         push si
  425.         dec si
  426.  
  427.         mov ax, si        ; Jump
  428.         mov cx, y_prompt    ;   the
  429.         add ax, cx        ;     %prompt
  430.         mov si, ax        ;       string.
  431.  
  432. ;        Display the prompt.
  433. prompt1:
  434.         lodsb            ; Scan for
  435.         cmp al, 0dh        ;   a return.
  436.         jz prompt2
  437.  
  438.         call make_char        ; Generate character.
  439.         mov dl, al        ; Output Character.
  440.         mov ah, 02h
  441.         int 21h
  442.         jmp prompt1
  443. prompt2:
  444.         pop si
  445.         push si
  446.         mov di, si
  447.         mov bx, di
  448.  
  449. ;        Check do we time out.
  450.         cmp v_timo, 00h        ; Do we timeout?
  451.         jnz check0        ; Yes. Jumpout.
  452.         jmp prompt3
  453.  
  454. check0:
  455. ;        Get the current time, and set the stop time.
  456.         mov ah, 2ch        ; Get the
  457.         int 21h            ;   current time.
  458.         mov dl, d_ent        ; No day.
  459.  
  460.         add dh, s_ent        ; Add the seconds
  461.         cmp dh, 3ch
  462.         jb get0
  463.         sub dh, 3ch        ; and correct.
  464.         inc cl
  465. get0:
  466.         add cl, m_ent        ; Add the minutes
  467.         cmp cl, 3ch
  468.         jb get1
  469.         sub cl, 3ch        ; and correct.
  470.         inc ch
  471. get1:
  472.         add ch, h_ent        ; Add the hours
  473.         cmp ch, 18h
  474.         jb get2
  475.         sub ch, 18h        ; and correct.
  476.         inc dl            ; New day.
  477. get2:
  478.         mov s_stt, dh        ; Save
  479.         mov m_stt, cl        ;   the
  480.         mov h_stt, ch        ;     stop
  481.         mov d_stt, dl        ;       time.
  482. ;        end of get and set time.
  483.  
  484. ;        Get and check time.
  485.         mov al, 00h        ; Set for
  486.         mov f_stt, al        ;   read input.
  487.  
  488.         mov ah, 33h        ; Check Ctrl-Break.
  489.         mov al, 00h
  490.         int 21
  491.         mov c_brk, dl        ; Save current setting.
  492.         mov ah, 33h        ; Set Ctrl-Break.
  493.         mov al, 01h
  494.         mov dl, 01h
  495.         int 21
  496. check1:
  497.         mov ah, 0bh        ; Check
  498.         int 21h            ;   input
  499.         cmp al, 00h        ;     waiting.
  500.         jnz check9        ; Yes. Jump out.
  501.  
  502.         mov ah, 2ch        ; Get the
  503.         int 21h            ;   current time.
  504.  
  505.         cmp d_stt, 00h        ; Over a midnight?
  506.         jz check3
  507.         cmp ch, 00h        ; New hour?
  508.         jnz check1
  509.         cmp cl, 00h        ; New minute?
  510.         jnz check1
  511.         cmp dh, 00h        ; New second?
  512.         jnz check1
  513.         cmp dl, 00h        ; New hundredth second?
  514.         jz check1
  515.         mov al, d_stt        ; Decrement
  516.         dec al            ;   a day
  517.         mov d_stt, al        ;     and save.
  518. check2:
  519.         mov ah, 2ch        ; Get the
  520.         int 21h            ;   current time.
  521.  
  522.         cmp dh, 00h        ; Loop until
  523.         jz check2        ;   the second changes.
  524.  
  525.         jmp check1
  526.  
  527. check3:
  528.         cmp ch, h_stt        ; Correct hour?
  529.         jb check1        ; No. Loop.
  530.         cmp cl, m_stt        ; Correct minute?
  531.         jb check1        ; No. Loop.
  532.         cmp dh, s_stt        ; Correct second?
  533.         jb check1        ; No. Loop.
  534.         mov al, 01h        ; Set for
  535.         mov f_stt, al        ;   timeout.
  536.  
  537. check9:
  538.         mov ah, 33h        ; Restore Ctrl-Break.
  539.         mov al, 01h
  540.         mov dl, c_brk
  541.         int 21
  542.  
  543.         cmp f_stt, 00h        ; Is someone typing?
  544.         jz prompt3        ; Yes. Jump out.
  545.         mov al, 0dh        ; Fake carriage return read
  546.         jmp prompt7
  547.  
  548. ;        end of check time.
  549.  
  550. prompt3:
  551. ;        Read the response.
  552.         mov ah, 08h        ; Read keyboard.
  553.         int 21h
  554.  
  555.         cmp v_upper, 01h    ; Upper case on.
  556.         jnz not_upper
  557.         call uppercase        ; Convert to uppercase.
  558. not_upper:
  559.  
  560.         cmp v_lower, 01h    ; Lower case on.
  561.         jnz not_lower
  562.         call lowercase        ; Convert to lowercase.
  563. not_lower:
  564.  
  565.         cmp al, 08h        ; Got a backspace character.
  566.         jz prompt4
  567.         cmp al, 7fh        ; Got a delete character.
  568.         jnz prompt6
  569.  
  570. prompt4:
  571.         mov dx, di        ; Current pointer.
  572.         cmp bx, dx        ; Have we moved?
  573.         jz prompt3        ; No. Jump.
  574.  
  575.         cmp v_echo, 00h        ; Do we echo the character.
  576.         jnz prompt5
  577.  
  578.         mov dl, 08h        ; Print a backspace.
  579.         mov ah, 02h
  580.         int 21h
  581.  
  582.         mov dl, " "        ; Print a space.
  583.         mov ah, 02h
  584.         int 21h
  585.  
  586.         mov dl, 08h        ; Print a backspace.
  587.         mov ah, 02h
  588.         int 21h
  589.  
  590. prompt5:
  591.         dec di
  592.         cmp v_echo, 00h        ; Do we echo the character.
  593.         jmp prompt3
  594.  
  595. prompt6:
  596.         cmp v_echo, 00h        ; Do we echo the character.
  597.         jnz prompt7
  598.  
  599.         mov dl, al        ; Output Character.
  600.         mov ah, 02h
  601.         int 21h
  602.  
  603. prompt7:
  604.         cmp al, " "        ; Is it a space.
  605.         jnz not_space
  606.  
  607.         cmp v_trim, 01h        ; Trim leading space.
  608.         jz prompt3
  609.  
  610. not_space:
  611.         mov v_trim, 00h        ; No Trim.
  612.  
  613.         stosb            ; Save the byte.
  614.         cmp al, 0dh        ; Got a return.
  615.         jnz prompt3
  616.  
  617.         mov dl, 0dh        ; Print a return.
  618.         mov ah, 02h
  619.         int 21h
  620.         mov dl, 0ah        ; Print a linefeed.
  621.         mov ah, 02h
  622.         int 21h
  623.  
  624.         cmp w_trim, 01h        ; Trim trailing space.
  625.         jnz trim_nosp
  626.         dec di
  627.  
  628. trim_sp:
  629.         dec di
  630.         mov al, [di]        ; Get a byte.
  631.  
  632.         cmp al, " "        ; Is is a space.
  633.         jz trim_sp        ; Yes. Loop.
  634.  
  635.         inc di
  636.         mov al, 0dh        ; Put in a carriage return.
  637.         stosb
  638.  
  639. trim_nosp:
  640.         pop si
  641.         push si
  642.         mov al, [si]
  643.         cmp al ,0dh        ; Is it a return.
  644.         jnz prompt9        ; No.  Jump out.
  645.  
  646.         mov di, si        ; Move
  647.         mov si, offset v_def    ;   the default
  648.         mov cx, x_def        ;     in place.
  649.         rep movsb
  650.  
  651.         mov al, 0dh
  652.         stosb
  653. prompt9:
  654.         pop si
  655.         pop di
  656.  
  657.         jmp get_data
  658.  
  659. ;        white space in front of function
  660. sub_fun:
  661.         mov si, di
  662. sub_fun0:
  663.         lodsb
  664.         mov o_tmp, si
  665.         cmp al, " "        ; Is it space?
  666.         jz sub_fun0        ; Yes. Ignore.
  667.         cmp al, 09h        ; Is it a tab?
  668.         jz sub_fun0        ; Yes. Ignore.
  669.         cmp al, "%"        ; Is it a special one.
  670.         jz echo         ; Yes.  Use it.
  671. sub_fun1:
  672.         dec si
  673.         mov ax, si        ; Get current pointer.
  674.         mov bx, o_prompt    ; Get prompt value start.
  675.         sub ax, bx        ; To get prompt noise length.
  676.         mov y_prompt, ax    ; Save it.
  677.  
  678.         jmp get_prompt
  679.  
  680.  
  681. ;        Handle %noecho.
  682. echo:
  683.         mov si, o_tmp        ; Set destination.
  684.         mov di, offset l_echo    ; Set Source.
  685.         mov cx, s_echo
  686.         rep cmpsb        ; Is it %noecho.
  687.         jz get_echo        ; Yes.
  688.  
  689.         mov si, o_tmp        ; Set destination.
  690.         mov di, offset u_echo    ; Set source.
  691.         mov cx, s_echo
  692.         rep cmpsb        ; Is it %NOECHO.
  693.         jz get_echo        ; Yes.
  694.  
  695.         jmp upper
  696.  
  697. get_echo:
  698.         mov v_echo, 01h        ; Set no echo.
  699.         jmp sub_fun0
  700.  
  701. ;        Handle %upper.
  702. upper:
  703.         mov si, o_tmp        ; Set destination.
  704.         mov di, offset l_upper    ; Set Source.
  705.         mov cx, s_upper
  706.         rep cmpsb        ; Is it %upper.
  707.         jz get_upper        ; Yes.
  708.  
  709.         mov si, o_tmp        ; Set destination.
  710.         mov di, offset u_upper    ; Set source.
  711.         mov cx, s_upper
  712.         rep cmpsb        ; Is it %UPPER.
  713.         jz get_upper        ; Yes.
  714.  
  715.         jmp lower
  716.  
  717. get_upper:
  718.         mov v_upper, 01h    ; Set upper case.
  719.         jmp sub_fun0
  720.  
  721. ;        Handle %lower.
  722. lower:
  723.         mov si, o_tmp        ; Set destination.
  724.         mov di, offset l_lower    ; Set Source.
  725.         mov cx, s_lower
  726.         rep cmpsb        ; Is it %lower.
  727.         jz get_lower        ; Yes.
  728.  
  729.         mov si, o_tmp        ; Set destination.
  730.         mov di, offset u_lower    ; Set source.
  731.         mov cx, s_lower
  732.         rep cmpsb        ; Is it %LOWER.
  733.         jz get_lower        ; Yes.
  734.  
  735.         jmp trim
  736.  
  737. get_lower:
  738.         mov v_lower, 01h    ; Set lower case.
  739.         jmp sub_fun0
  740.  
  741. ;        Handle %trim.
  742. trim:
  743.         mov si, o_tmp        ; Set destination.
  744.         mov di, offset l_trim    ; Set Source.
  745.         mov cx, s_trim
  746.         rep cmpsb        ; Is it %trim.
  747.         jz get_trim        ; Yes.
  748.  
  749.         mov si, o_tmp        ; Set destination.
  750.         mov di, offset u_trim    ; Set source.
  751.         mov cx, s_trim
  752.         rep cmpsb        ; Is it %TRIM.
  753.         jz get_trim        ; Yes.
  754.  
  755.         jmp timo
  756.  
  757. get_trim:
  758.         mov v_trim, 01h        ; Trim leading spaces.
  759.         mov w_trim, 01h        ; Trim trailing spaces.
  760.         jmp sub_fun0
  761.  
  762. ;        Handle %timo.
  763. timo:
  764.         mov si, o_tmp        ; Set destination.
  765.         mov di, offset l_timo    ; Set Source.
  766.         mov cx, s_timo
  767.         rep cmpsb        ; Is it %timo.
  768.         jz get_timo        ; Yes.
  769.  
  770.         mov si, o_tmp        ; Set destination.
  771.         mov di, offset u_timo    ; Set source.
  772.         mov cx, s_timo
  773.         rep cmpsb        ; Is it %TIMO.
  774.         jz get_timo        ; Yes.
  775.  
  776.         jmp default
  777.  
  778. get_timo:
  779. ;        mov si, di
  780. timo1:
  781.         lodsb
  782.         cmp al, ":"        ; Time
  783.         jz timo2        ;   dividers
  784.         cmp al, "."        ;     semi-colon
  785.         jz timo2        ;       and period.
  786.         cmp al, "-"
  787.         jz timo2
  788.  
  789.         cmp al, "0"        ; Is
  790.         jb timo3        ;   it
  791.         cmp al, "9"        ;     a 
  792.         jg timo3        ;       digit?
  793.  
  794.         sub al, 30h        ; Make it binary.
  795.         mov bh, al        ; Temp. save it.
  796.         mov al, s_ent        ; Get the seconds.
  797.         mov bl, 0ah        ; Multiply 
  798.         mul bl            ;   by ten.
  799.         add al, bh        ; Add next digit.
  800.         mov s_ent, al        ; Save the seconds.
  801.         jmp timo1
  802.  
  803. timo2:
  804.         mov al, h_ent
  805.         mov d_ent, al
  806.         mov al, m_ent        ; Roll
  807.         mov h_ent, al        ;   over
  808.         mov al, s_ent        ;     the time
  809.         mov m_ent, al        ;       components.
  810.         mov al, 00h
  811.         mov s_ent, al
  812.         jmp timo1
  813.  
  814. timo3:
  815.         mov v_timo, 01h        ; Set time out.
  816.         dec si
  817.         jmp sub_fun0
  818.  
  819. ;        Handle %def.
  820. default:
  821.         mov si, o_tmp        ; Set destination.
  822.         mov di, offset l_def    ; Set Source.
  823.         mov cx, s_def
  824.         rep cmpsb        ; Is it %def.
  825.         jz get_default        ; Yes.
  826.  
  827.         mov si, o_tmp        ; Set destination.
  828.         mov di, offset u_def    ; Set source.
  829.         mov cx, s_def
  830.         rep cmpsb        ; Is it %DEF.
  831.         jz get_default        ; Yes.
  832.  
  833.         mov si, o_tmp
  834.         jmp sub_fun1
  835.  
  836. get_default:
  837.         lodsb            ; Get the delimiter.
  838.         mov dl, al        ; Save it.
  839.         mov di, offset v_def    ; Get address for save of value.
  840.         mov x_def, si        ; Save the start of the value.
  841. default1:
  842.         lodsb            ; Get a byte.
  843.         cmp al, 0dh        ; Is it a return?
  844.         jz default2        ; Yes. Jump out.
  845.  
  846.         cmp al, dl        ; Is it the delimiter?
  847.         jz default3        ; Yes. Jump out.
  848.         stosb            ; Save it.
  849.         jmp default1
  850. default2:
  851.         mov -1[si], dl        ; No
  852.         mov ah, " "        ;   delimiter
  853.         mov [si], ah        ;     so
  854.         mov ah, ">"        ;       create
  855.         mov 1[si], ah        ;         the
  856.         mov 2[si], al        ;           info.
  857.         dec si
  858.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  859.         jmp default1
  860.  
  861. default3:
  862.         mov ax, si        ; Get current pointer.
  863.         mov bx, x_def        ; Get default value start.
  864.         sub ax, bx        ; To get length of default value.
  865.         dec ax
  866.         mov x_def, ax        ; Save it.
  867.  
  868.         jmp sub_fun0
  869.  
  870. ;        Handle %rep.
  871. replace:
  872.         pop si
  873.         push si
  874.         mov di, si        ; Set destination.
  875.         mov si, offset l_rep    ; Set Source.
  876.         mov cx, s_rep
  877.         rep cmpsb        ; Is it %rep.
  878.         jz get_replace        ; Yes.
  879.  
  880.         pop si
  881.         push si
  882.         mov di, si        ; Set destination.
  883.         mov si, offset u_rep    ; Set Source.
  884.         mov cx, s_rep
  885.         rep cmpsb        ; Is it %REP.
  886.         jz get_replace        ; Yes.
  887.  
  888.         jmp chgup        ; No. Jump out.
  889.  
  890. get_replace:
  891.         mov si, di
  892.         lodsb            ; Get the delimiter.
  893.         mov dl, al        ; Save it.
  894.         mov di, offset d_arg1    ; Get address for save of value.
  895.         mov cx, 00h
  896. replace1:
  897.         lodsb            ; Get a byte.
  898.         cmp al, 0dh        ; Is it a return?
  899.         jz replace2        ; Yes. Jump out.
  900.  
  901.         cmp al, dl        ; Is it the delimiter?
  902.         jz replace3        ; Yes. Jump out.
  903.         stosb            ; Save it.
  904.         inc cx            ; Increment the count
  905.         jmp replace1
  906. replace2:
  907.         dec si
  908.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  909. ;        You could take out the next line.
  910.         jmp nor_term        ; Exit.
  911.  
  912. replace3:
  913.         mov s_arg1, cx        ; Save size.
  914.         mov di, offset d_arg2    ; Get address for save of value.
  915.         mov cx, 00h
  916. replace4:
  917.         lodsb            ; Get a byte.
  918.         cmp al, 0dh        ; Is it a return?
  919.         jz replace5        ; Yes. Jump out.
  920.  
  921.         cmp al, dl        ; Is it the delimiter?
  922.         jz replace6        ; Yes. Jump out.
  923.         stosb            ; Save it.
  924.         inc cx            ; Increment the count
  925.         jmp replace4
  926.  
  927. replace5:
  928.         dec si
  929.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  930. replace6:
  931.         mov s_arg2, cx        ; Save size.
  932.         mov v_rep, 0ffh        ; Flag the replace.
  933.  
  934.         pop si
  935.         pop di
  936.         inc si
  937.         jmp data_end
  938.  
  939. ;        Handle %chgup.
  940. chgup:
  941.         pop si
  942.         push si
  943.         mov di, si        ; Set destination.
  944.         mov si, offset l_chgup    ; Set Source.
  945.         mov cx, s_chgup
  946.         rep cmpsb        ; Is it %chgup.
  947.         jz get_chgup        ; Yes.
  948.  
  949.         pop si
  950.         push si
  951.         mov di, si        ; Set destination.
  952.         mov si, offset u_chgup    ; Set Source.
  953.         mov cx, s_chgup
  954.         rep cmpsb        ; Is it %CHGUP.
  955.         jz get_chgup        ; Yes.
  956.  
  957.         jmp chglo        ; No. Jump out.
  958.  
  959. get_chgup:
  960.         mov v_chgup, 0ffh
  961.         pop si
  962.         pop di
  963.         inc si
  964.         jmp data_end
  965.  
  966. ;        Handle %chglo.
  967. chglo:
  968.         pop si
  969.         push si
  970.         mov di, si        ; Set destination.
  971.         mov si, offset l_chglo    ; Set Source.
  972.         mov cx, s_chglo
  973.         rep cmpsb        ; Is it %chglo.
  974.         jz get_chglo        ; Yes.
  975.  
  976.         pop si
  977.         push si
  978.         mov di, si        ; Set destination.
  979.         mov si, offset u_chglo    ; Set Source.
  980.         mov cx, s_chglo
  981.         rep cmpsb        ; Is it %CHGLO.
  982.         jz get_chglo        ; Yes.
  983.  
  984.         jmp logical        ; No. Jump out.
  985.  
  986. get_chglo:
  987.         mov v_chglo, 0ffh
  988.         pop si
  989.         pop di
  990.         inc si
  991.         jmp data_end
  992.  
  993. ;        handle %{operator}
  994. logical:
  995.         pop si
  996.         push si
  997.         lodsb            ; Get a byte.
  998.         mov ah, al        ; First byte.                
  999.         lodsb            ; Second byte.
  1000.  
  1001.         mov dx, l_eq        ; Is
  1002.         cmp ax, dx        ;   it
  1003.         jz equal        ;     eq.
  1004.         mov dx, u_eq        ; Is
  1005.         cmp ax, dx        ;   it
  1006.         jz equal        ;     EQ.
  1007.  
  1008.         mov dx, l_lt        ; Is
  1009.         cmp ax, dx        ;   it
  1010.         jz less_than        ;     lt.
  1011.         mov dx, u_lt        ; Is
  1012.         cmp ax, dx        ;   it
  1013.         jz less_than        ;     LT.
  1014.  
  1015.         mov dx, l_le        ; Is
  1016.         cmp ax, dx        ;   it
  1017.         jz less_equal        ;     le.
  1018.         mov dx, u_le        ; Is
  1019.         cmp ax, dx        ;   it
  1020.         jz less_equal        ;     LE.
  1021.  
  1022.         mov dx, l_gt        ; Is
  1023.         cmp ax, dx        ;   it
  1024.         jz greater_than        ;     gt.
  1025.         mov dx, u_gt        ; Is
  1026.         cmp ax, dx        ;   it
  1027.         jz greater_than        ;     GT.
  1028.  
  1029.         mov dx, l_ge        ; Is
  1030.         cmp ax, dx        ;   it
  1031.         jz greater_equal    ;     ge.
  1032.         mov dx, u_ge        ; Is
  1033.         cmp ax, dx        ;   it
  1034.         jz greater_equal    ;     GE.
  1035.  
  1036.         pop si
  1037.         pop di
  1038.         dec si
  1039.         jmp get_data        ; No. Jump out.
  1040.  
  1041.  
  1042. equal:
  1043.         mov e_oper, 0ffh    ; Set for equal.
  1044.         jmp arg_one
  1045.  
  1046. less_equal:
  1047.         mov e_oper, 0ffh    ; Set for equal.
  1048. less_than:
  1049.         mov l_oper, 0ffh    ; Set for less than.
  1050.         jmp arg_one
  1051.  
  1052. greater_equal:
  1053.         mov e_oper, 0ffh    ; Set for equal.
  1054. greater_than:
  1055.         mov g_oper, 0ffh    ; Set for greater than.
  1056.         jmp arg_one
  1057.  
  1058. ;        Get argument one.
  1059. arg_one:
  1060.         lodsb            ; Get a byte.
  1061.         cmp al, " "        ; Is it a space.
  1062.         jz test_arg1
  1063.         cmp al, 09h        ; Is it a tab.
  1064.         jz test_arg1
  1065.         cmp al, "'"        ; Is it a quote.
  1066.         jz quote1
  1067.         cmp al, '"'        ; Is it a quote.
  1068.         jz quote1
  1069.  
  1070.         jmp log_exit
  1071.  
  1072. quote1:
  1073.         mov di, offset d_arg1    ; Address of argument one.
  1074.         call get_quote        ; Get the quoted string.
  1075.  
  1076.         cmp exit_code, 06h    ; Unmatched quote?
  1077.         jz test_end
  1078.  
  1079.         mov s_arg1, cx        ; Save the size.
  1080.         jmp arg_two
  1081.  
  1082. test_arg1:
  1083.         lodsb            ; Get a byte.
  1084.         cmp al, " "        ; Is it a space.
  1085.         jz test_arg1
  1086.         cmp al, 09h        ; Is it a tab.
  1087.         jz test_arg1
  1088.         cmp al, "'"        ; Is it a quote.
  1089.         jz quote1
  1090.         cmp al, '"'        ; Is it a quote.
  1091.         jz quote1
  1092.         cmp al, 0dh        ; Is it a carriage return.
  1093.         jz no_argum
  1094.  
  1095.         dec si
  1096.         call get_var0        ; Get the variable.
  1097.  
  1098.         cmp exit_code, 08h    ; Variable not found?
  1099.         jz test_end
  1100.  
  1101.         dec si
  1102.         mov di, offset d_arg1    ; Set argument one.
  1103.         call copy_env        ; Copy the data out.
  1104.         mov s_arg1, cx        ; Save the size.
  1105.  
  1106. ;        Get argument two
  1107. arg_two:
  1108.         lodsb            ; Get a byte.
  1109.         cmp al, " "        ; Is it a space.
  1110.         jz arg_two
  1111.         cmp al, 09h        ; Is it a tab.
  1112.         jz arg_two
  1113.         cmp al, "'"        ; Is it a quote.
  1114.         jz quote2
  1115.         cmp al, '"'        ; Is it a quote.
  1116.         jz quote2
  1117.  
  1118.         cmp al, 0dh        ; Is it a carriage return.
  1119.         jnz test_arg2
  1120. no_argum:
  1121.         mov cs:[exit_code], 07h    ; Not a valid argument.
  1122.         jmp test_end        ; Exit.        
  1123.  
  1124. test_end:
  1125.         mov al, "E"        ; Error status.
  1126.         jmp log_end
  1127.  
  1128. quote2:
  1129.         mov di, offset d_arg2    ; Address of argument two.
  1130.         call get_quote        ; Get the quoted string.
  1131.  
  1132.         cmp exit_code, 06h    ; Unmatched quote?
  1133.         jz test_end
  1134.  
  1135.         mov s_arg2, cx        ; Save the size.
  1136.         jmp log_test
  1137.  
  1138. test_arg2:
  1139.         dec si
  1140.         call get_var0        ; Get the variable.
  1141.  
  1142.         cmp exit_code, 08h    ; Variable not found?
  1143.         jz test_end
  1144.  
  1145.         mov di, offset d_arg2    ; Set argument two.
  1146.         call copy_env        ; Copy the data out.
  1147.         mov s_arg2, cx        ; Save the size.
  1148.  
  1149. log_test:
  1150.         mov ax, offset d_arg1    ; Argument one.
  1151.         mov cx, s_arg1        ; Argument size.
  1152.         add ax, cx        ; At end of argument.
  1153.         mov si, ax        ; Set source.
  1154.  
  1155.         mov ax, offset d_arg2    ; Argument two.
  1156.         mov dx, s_arg2        ; Argument size.
  1157.         add ax, dx        ; At end of argument.
  1158.         mov di, ax        ; Set destination.
  1159.  
  1160. log_loop:
  1161.         cmp cx, 00h        ; Arg1 ran out of bytes.
  1162.         jz log_arg1
  1163.  
  1164.         cmp dx, 00h        ; Arg2 ran out of bytes.
  1165.         jz log_arg2
  1166.  
  1167.         dec si
  1168.         mov al, [si]        ; Get an arg1 byte.
  1169.         dec cx
  1170.  
  1171.         dec di
  1172.         mov bl, [di]        ; Get an arg2 byte.
  1173.         dec dx
  1174.  
  1175.         cmp al, bl        ; Are the equal?
  1176.         jz log_loop        ; Yes. Loop.
  1177.  
  1178.         jg log_great        ; Go to test for greater than.
  1179.  
  1180.         cmp l_oper, 0ffh    ; Less than operator?
  1181.         jz log_true        ; Yes. Then true.
  1182.  
  1183.         jmp log_false        ; No. Than false.
  1184.  
  1185. log_arg1:
  1186.         cmp dx, 00h        ; Arg2 ran out of bytes.
  1187.         jz log_equal
  1188.  
  1189.         cmp g_oper, 0ffh    ; Greater than operator?
  1190.         jz log_true        ; Yes. Then true.
  1191.         jmp log_false
  1192.  
  1193. log_arg2:
  1194.         cmp l_oper, 0ffh    ; Less than operator?
  1195.         jz log_true        ; Yes. Then true.
  1196.         jmp log_false
  1197.  
  1198. log_equal:
  1199.         cmp e_oper, 0ffh    ; Equal operator?
  1200.         jz log_true        ; Yes. Then true.
  1201.         jmp log_false
  1202.  
  1203. log_great:
  1204.         cmp g_oper, 0ffh    ; Greater than operator?
  1205.         jz log_true        ; Yes. Then true.
  1206. log_false:
  1207.         mov al, "F"        ; Test is false.
  1208.         jmp log_end
  1209.  
  1210. log_true:
  1211.         mov al, "T"        ; Test is true.
  1212.  
  1213. log_end:
  1214.         pop si
  1215.         push si
  1216.         dec si
  1217.         mov di, si        ; Move
  1218.         stosb            ;   in
  1219.         mov al, 0dh        ;     the
  1220.         stosb            ;        status.
  1221.  
  1222. log_exit:
  1223.         pop si
  1224.         pop di
  1225.         dec si
  1226.         jmp get_data        ; No. Jump out.
  1227.  
  1228.  
  1229. ;        Get the quoted string
  1230. get_quote:
  1231.         mov cx, 00h        ; Zero the counter.
  1232.         mov dl, al        ; Save the single quote.
  1233.  
  1234. get_quote1:
  1235.         lodsb            ; Get a byte.
  1236.         cmp al, " "        ; Is it a space.
  1237.         jz get_quote1
  1238.         cmp al, 09h        ; Is it a tab.
  1239.         jz get_quote1
  1240.         dec si
  1241.  
  1242. get_quote2:
  1243.         lodsb            ; Get a byte.
  1244.         cmp al, dl        ; Is it the end.
  1245.         jz get_quote4
  1246.  
  1247.         cmp al, 0dh        ; Is it the end of the command.
  1248.         jz get_quote3
  1249.  
  1250.         stosb            ; Save the byte.
  1251.         inc cx            ; Count the byte.
  1252.         jmp get_quote2
  1253.  
  1254. get_quote3:
  1255.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  1256.  
  1257. get_quote4:
  1258.         ret
  1259.  
  1260.  
  1261. ;        Get variable data
  1262. get_var0:
  1263.         mov cx, 00h        ; Zero the counter.
  1264.         mov s_env, cx        ; Zero for use.
  1265.         mov di, offset n_env    ; Address of variable.
  1266.  
  1267. get_var1:
  1268.         lodsb            ; Get a byte.
  1269.         cmp al, " "        ; Is it the end of the variable?
  1270.         jz get_var2        ; Yes.  Jump out.
  1271.         cmp al, 09h        ; Is it the end of the variable?
  1272.         jz get_var2        ; Yes.  Jump out.
  1273.         cmp al, 0dh        ; Is it a carriage return.
  1274.         jz get_var2
  1275.  
  1276.         call uppercase        ; Convert to uppercase.
  1277.         stosb            ; Save the byte.
  1278.         inc cx            ; Count the byte.
  1279.         jmp get_var1
  1280.  
  1281. get_var2:
  1282.         cmp cx, 00h        ; Is there a variable name?
  1283.         jz get_var3
  1284.  
  1285.         mov s_env, cx        ; Variable name length.
  1286.         call loc_env        ; Get env variable base/offset.
  1287.         cmp f_env, 00h        ; Did we find the variable?
  1288.         jz get_var4
  1289.  
  1290. get_var3:
  1291.         mov cs:[exit_code], 08h    ; Variable not found.
  1292.  
  1293. get_var4:
  1294.         ret
  1295.  
  1296.  
  1297. percent:
  1298.         mov al, 1[si]
  1299.         cmp al, "+"        ; Is it a plus.
  1300.         jz off_drive
  1301.  
  1302.         cmp al, "-"        ; Is it a minus.
  1303.         jnz cwd
  1304.  
  1305. ;        Offset from a given drive.
  1306. off_drive:
  1307.         mov dh, al        ; Save the sign.
  1308.         mov dl, 2[si]
  1309.         cmp dl, "0"        ; Is
  1310.         jb off_drive0        ;   it
  1311.         cmp dl, "9"        ;     a
  1312.         jg off_drive0        ;       number.
  1313.         sub dl, 30h        ; Make it binary.
  1314.  
  1315.         mov ah, 19h        ; Get the disk drive.
  1316.         int 21h
  1317.  
  1318.         add al, "a"        ; Make it a letter.
  1319.         cmp dh, "+"
  1320.         jz off_drive1
  1321.         sub al, dl        ; Subtract from current drive.
  1322.         cmp al, "a"        ; If less then A
  1323.         jge off_drive2        ;   we have an error.
  1324. let_error:
  1325.         mov exit_code, 09h    ; Offset not valid.
  1326.         mov al, "%"        ; Put percent back.
  1327. off_drive0:
  1328.         jmp get_next
  1329.  
  1330. off_drive1:
  1331.         add al, dl        ; Add from current drive.
  1332.         cmp al, "z"        ; If greater then Z
  1333.         jg let_error        ;   we have an error.
  1334.  
  1335. off_drive2:
  1336.         stosb            ; Save the letter.
  1337.         inc si            ; Skip
  1338.         inc si            ;   over
  1339.         inc si            ;     %+n, or %-n.
  1340.  
  1341.         jmp get_data
  1342.  
  1343.  
  1344. ;        Handle %cwd.
  1345. cwd:
  1346.         push di
  1347.         push si
  1348.  
  1349.         mov di, si        ; Set destination.
  1350.         inc di
  1351.         mov si, offset l_cwd    ; Set Source.
  1352.         mov cx, s_cwd
  1353.         rep cmpsb        ; Is it %cwd.
  1354.         jz get_cwd        ; Yes.
  1355.  
  1356.         pop si
  1357.         push si
  1358.         mov di, si        ; Set destination.
  1359.         inc di
  1360.         mov si, offset u_cwd    ; Set source.
  1361.         mov cx, s_cwd
  1362.         rep cmpsb        ; Is it %CWD.
  1363.         jz get_cwd        ; Yes.
  1364.  
  1365.         pop si
  1366.         pop di
  1367.         jmp cfd            ; No. Jump out.
  1368.  
  1369. get_cwd:
  1370.         mov bx, di
  1371.         pop si
  1372.         pop di
  1373.         mov si, bx
  1374.  
  1375.         mov al, "\"        ; Put in the
  1376.         stosb            ;   root backslash.
  1377.         push si
  1378.         mov si, offset d_cwd    ; Place to put the directory name.
  1379.  
  1380.         mov ah, 47h        ; Get current directory.
  1381.         mov dl, 00h        ; Current disk drive.
  1382.         int 21h
  1383.  
  1384. cwd1:
  1385.         lodsb            ; Find the
  1386.         cmp al, 00h        ;   string
  1387.         jz cwd2            ;     terminator (zero).
  1388.  
  1389.         stosb            ; Store it.
  1390.         jmp cwd1
  1391.  
  1392. cwd2:
  1393.         pop si
  1394.         jmp get_data
  1395.  
  1396.  
  1397. ;        Handle %cfd.
  1398. cfd:
  1399.         push di
  1400.         push si
  1401.  
  1402.         mov di, si        ; Set destination.
  1403.         inc di
  1404.         mov si, offset l_cfd    ; Set Source.
  1405.         mov cx, s_cfd
  1406.         rep cmpsb        ; Is it %cfd.
  1407.         jz get_cfd        ; Yes.
  1408.  
  1409.         pop si
  1410.         push si
  1411.         mov di, si        ; Set destination.
  1412.         inc di
  1413.         mov si, offset u_cfd    ; Set source.
  1414.         mov cx, s_cfd
  1415.         rep cmpsb        ; Is it %CFD.
  1416.         jz get_cfd        ; Yes.
  1417.  
  1418.         pop si
  1419.         pop di
  1420.         jmp dosv        ; No. Jump out.
  1421.  
  1422. get_cfd:
  1423.         mov bx, di
  1424.         pop si
  1425.         pop di
  1426.         mov si, bx
  1427.  
  1428.         push si
  1429.         mov si, offset d_cwd    ; Place to put the directory name.
  1430.  
  1431.         mov ah, 47h        ; Get current directory.
  1432.         mov dl, 00h        ; Current disk drive.
  1433.         int 21h
  1434.  
  1435.         mov al, [si]        ; Is it the
  1436.         cmp al, 00h        ;   string
  1437.         jz cfd2            ;     terminator (zero).
  1438.  
  1439.         mov al, "\"        ; Put in the
  1440.         stosb            ;   root backslash.
  1441. cfd1:
  1442.         lodsb            ; Find the
  1443.         cmp al, 00h        ;   string
  1444.         jz cfd2            ;     terminator (zero).
  1445.  
  1446.         stosb            ; Store it.
  1447.         jmp cfd1
  1448.  
  1449. cfd2:
  1450.         mov al, "\"        ; Put in the
  1451.         stosb            ;   end backslash.
  1452.         pop si
  1453.         jmp get_data
  1454.  
  1455.  
  1456. ;        Handle %dosv.
  1457. dosv:
  1458.         push di
  1459.         push si
  1460.  
  1461.         mov di, si        ; Set destination.
  1462.         inc di
  1463.         mov si, offset l_dosv    ; Set Source.
  1464.         mov cx, s_dosv
  1465.         rep cmpsb        ; Is it %dosv.
  1466.         jz get_dosv        ; Yes.
  1467.  
  1468.         pop si
  1469.         push si
  1470.         mov di, si        ; Set destination.
  1471.         inc di
  1472.         mov si, offset u_dosv    ; Set source.
  1473.         mov cx, s_dosv
  1474.         rep cmpsb        ; Is it %DOSV.
  1475.         jz get_dosv        ; Yes.
  1476.  
  1477.         pop si
  1478.         pop di
  1479.         jmp dosm        ; No. Jump out.
  1480.  
  1481. get_dosv:
  1482.         mov bx, di
  1483.         pop si
  1484.         pop di
  1485.         mov si, bx
  1486.  
  1487.         mov ah, 30h        ; Get DOS version number.
  1488.         int 21h
  1489.  
  1490.         add al, "0"        ; Make it a number.
  1491.         stosb            ; Store it.
  1492.  
  1493.         jmp get_data
  1494.  
  1495.  
  1496. ;        Handle %dosm.
  1497. dosm:
  1498.         push di
  1499.         push si
  1500.  
  1501.         mov di, si        ; Set destination.
  1502.         inc di
  1503.         mov si, offset l_dosm    ; Set Source.
  1504.         mov cx, s_dosm
  1505.         rep cmpsb        ; Is it %dosm.
  1506.         jz get_dosm        ; Yes.
  1507.  
  1508.         pop si
  1509.         push si
  1510.         mov di, si        ; Set destination.
  1511.         inc di
  1512.         mov si, offset u_dosm    ; Set source.
  1513.         mov cx, s_dosm
  1514.         rep cmpsb        ; Is it %DOSM.
  1515.         jz get_dosm        ; Yes.
  1516.  
  1517.         pop si
  1518.         pop di
  1519.         jmp drive        ; No. Jump out.
  1520.  
  1521. get_dosm:
  1522.         mov bx, di
  1523.         pop si
  1524.         pop di
  1525.         mov si, bx
  1526.  
  1527.         mov ah, 30h        ; Get DOS version number.
  1528.         int 21h
  1529.  
  1530.         mov al, ah        ; Get minor version.
  1531.         cmp al, 0ah        ; Is it less then ten.
  1532.         jb dosm0        ; Yes. Jump out.
  1533.  
  1534.         call ascii        ; Do the minor version
  1535.         jmp dosm1
  1536. dosm0:
  1537.         add al, "0"        ; Make it a number.
  1538.         stosb            ; Store it.
  1539.  
  1540. dosm1:
  1541.         jmp get_data
  1542.  
  1543. ;        Handle %drive.
  1544. drive:
  1545.         push di
  1546.         push si
  1547.  
  1548.         mov di, si        ; Set destination.
  1549.         inc di
  1550.         mov si, offset l_drive    ; Set Source.
  1551.         mov cx, s_drive
  1552.         rep cmpsb        ; Is it %drive.
  1553.         jz get_drive        ; Yes.
  1554.  
  1555.         pop si
  1556.         push si
  1557.         mov di, si        ; Set destination.
  1558.         inc di
  1559.         mov si, offset u_drive    ; Set source.
  1560.         mov cx, s_drive
  1561.         rep cmpsb        ; Is it %DRIVE.
  1562.         jz get_drive        ; Yes.
  1563.  
  1564.         pop si
  1565.         pop di
  1566.         jmp time        ; No. Jump out.
  1567.  
  1568. get_drive:
  1569.         mov bx, di
  1570.         pop si
  1571.         pop di
  1572.         mov si, bx
  1573.  
  1574.         mov ah, 19h        ; Get the disk drive.
  1575.         int 21h
  1576.  
  1577.         add al, "a"        ; Make it a letter.
  1578.         stosb            ; Store it.
  1579.  
  1580.         jmp get_data
  1581.  
  1582.  
  1583. ;        Handle %time.
  1584. time:
  1585.         push di
  1586.         push si
  1587.  
  1588.         mov di, si        ; Set destination.
  1589.         inc di
  1590.         mov si, offset l_time    ; Set Source.
  1591.         mov cx, s_time
  1592.         rep cmpsb        ; Is it %time.
  1593.         jz get_time        ; Yes.
  1594.  
  1595.         pop si
  1596.         push si
  1597.         mov di, si        ; Set destination.
  1598.         inc di
  1599.         mov si, offset u_time    ; Set source.
  1600.         mov cx, s_time
  1601.         rep cmpsb        ; Is it %TIME.
  1602.         jz get_time        ; Yes.
  1603.  
  1604.         pop si
  1605.         pop di
  1606.         jmp date        ; No. Jump out.
  1607.  
  1608. get_time:
  1609.         mov bx, di
  1610.         pop si
  1611.         pop di
  1612.         mov si, bx
  1613.  
  1614.         mov ah, 2ch        ; Get the
  1615.         int 21h            ;   current time.
  1616.  
  1617.         mov bh, ":"        ; Separator.
  1618.         mov al, ch        ; Do the
  1619.         call ascii        ;   hours.
  1620.         mov al, bh        ; Do the
  1621.         stosb            ;   separator.
  1622.         mov al, cl        ; Do the
  1623.         call ascii        ;   minutes.
  1624.         mov al, bh        ; Do the
  1625.         stosb            ;   separator.
  1626.         mov al, dh        ; Do the
  1627.         call ascii        ;   seconds.
  1628.         
  1629.         jmp get_data
  1630.  
  1631.  
  1632. ;        Handle %date.
  1633. date:
  1634.         push di
  1635.         push si
  1636.  
  1637.         mov di, si        ; Set destination.
  1638.         inc di
  1639.         mov si, offset l_date    ; Set Source.
  1640.         mov cx, s_date
  1641.         rep cmpsb        ; Is it %date.
  1642.         jz get_date        ; Yes.
  1643.  
  1644.         pop si
  1645.         push si
  1646.         mov di, si        ; Set destination.
  1647.         inc di
  1648.         mov si, offset u_date    ; Set source.
  1649.         mov cx, s_date
  1650.         rep cmpsb        ; Is it %DATE.
  1651.         jz get_date        ; Yes.
  1652.  
  1653.         pop si
  1654.         pop di
  1655.         jmp character        ; No. Jump out.
  1656.  
  1657. get_date:
  1658.         mov bx, di
  1659.         pop si
  1660.         pop di
  1661.         mov si, bx
  1662.  
  1663.         lodsb            ; Get a byte.
  1664.         cmp al, "1"        ; Format one.
  1665.         jz date1        ; Yes. Jumpout.
  1666.         cmp al, "2"        ; Format two.
  1667.         jz date1        ; Yes. Jumpout.
  1668.         cmp al, "3"        ; Format three.
  1669.         jz date1        ; Yes. Jumpout.
  1670.         dec si
  1671.         mov al, z_date        ; Get the default.
  1672. date1:
  1673.         mov z_date, al        ; Save format.
  1674.         mov bh, "-"        ; Separator.
  1675.         
  1676.         mov ah, 2ah        ; Get the
  1677.         int 21h            ;   current date.
  1678.  
  1679.         cmp z_date, "3"
  1680.         jnz date2
  1681.         sub cx, 1900        ; Remove the century.
  1682.         mov al, cl        ; Do the
  1683.         call ascii        ;   year.
  1684.         mov al, bh        ; Do the
  1685.         stosb            ;   separator.
  1686. date2:
  1687.         cmp z_date, "1"
  1688.         jz date3
  1689.         mov al, dh        ; Do the
  1690.         call ascii        ;   month.
  1691.         mov al, bh        ; Do the
  1692.         stosb            ;   separator.
  1693. date3:
  1694.         mov al, dl        ; Do the
  1695.         call ascii        ;   Day.
  1696.  
  1697.         cmp z_date, "3"
  1698.         jz date9
  1699.         mov al, bh        ; Do the
  1700.         stosb            ;   separator.
  1701.  
  1702.         cmp z_date, "2"
  1703.         jz date4
  1704.  
  1705.         mov al, dh        ; Do the
  1706.         call ascii        ;   month.
  1707.         mov al, bh        ; Do the
  1708.         stosb            ;   separator.
  1709. date4:
  1710.         mov al, dh        ; Do the
  1711.         sub cx, 1900        ; Remove the century.
  1712.         mov al, cl        ; Do the
  1713.         call ascii        ;   year.
  1714.  
  1715. date9:        
  1716.         jmp get_data
  1717.  
  1718.  
  1719. ;        convert a binary number to two digit decimal.
  1720. ascii:
  1721.         mov bl, 0ah        ; Divide
  1722.         cbw            ;   by
  1723.         div bl            ;     ten.
  1724.         add al, "0"        ; Make it a number.
  1725.         stosb            ; Store tens.
  1726.         add ah, "0"        ; Make it a number.
  1727.         mov al, ah
  1728.         stosb            ; Store ones.
  1729.         ret
  1730.  
  1731.  
  1732. ;        Handle %chr.
  1733. character:
  1734.         push di
  1735.         push si
  1736.  
  1737.         mov di, si        ; Set destination.
  1738.         inc di
  1739.         mov si, offset l_chr    ; Set Source.
  1740.         mov cx, s_chr
  1741.         rep cmpsb        ; Is it %chr.
  1742.         jz get_character    ; Yes.
  1743.  
  1744.         pop si
  1745.         push si
  1746.         mov di, si        ; Set destination.
  1747.         inc di
  1748.         mov si, offset u_chr    ; Set Source.
  1749.         mov cx, s_chr
  1750.         rep cmpsb        ; Is it %CHR.
  1751.         jz get_character    ; Yes.
  1752.  
  1753.         pop si
  1754.         pop di
  1755.         jmp element        ; No. Jump out.
  1756.  
  1757. get_character:
  1758.         mov bx, di
  1759.         pop si
  1760.         pop di
  1761.         mov si, bx
  1762.  
  1763.         mov ax, 00h
  1764.         mov s_env, ax        ; Zero for use.
  1765.  
  1766.         lodsb            ; Get the delimiter.
  1767.         mov dl, al        ; Save it.
  1768.         push di
  1769.  
  1770.         call p_numb        ; Read number.
  1771.         mov n_chr, cx        ; Save element number.
  1772.  
  1773.         pop di
  1774.         cmp cx, 00h        ; Is it going to be a null.
  1775.         jz character1        ; No. Error.
  1776.  
  1777.         cmp cx, 0ffh        ; Is it valid?
  1778.         jbe character2        ; Yes. Jump out.
  1779.  
  1780. character1:
  1781.         mov cs:[exit_code], 09h    ; Range error.
  1782.         jmp nor_term        ; Exit.
  1783.  
  1784. character2:
  1785.         mov al, cl        ; Character is okay.
  1786.         stosb            ; Save the byte.
  1787.         jmp get_data
  1788.  
  1789.  
  1790. ;        Handle %elem.
  1791. element:
  1792.         push di
  1793.         push si
  1794.  
  1795.         mov di, si        ; Set destination.
  1796.         inc di
  1797.         mov si, offset l_elem    ; Set Source.
  1798.         mov cx, s_elem
  1799.         rep cmpsb        ; Is it %elem.
  1800.         jz get_element        ; Yes.
  1801.  
  1802.         pop si
  1803.         push si
  1804.         mov di, si        ; Set destination.
  1805.         inc di
  1806.         mov si, offset u_elem    ; Set Source.
  1807.         mov cx, s_elem
  1808.         rep cmpsb        ; Is it %ELEM.
  1809.         jz get_element        ; Yes.
  1810.  
  1811.         pop si
  1812.         pop di
  1813.         jmp substr        ; No. Jump out.
  1814.  
  1815. get_element:
  1816.         mov bx, di
  1817.         pop si
  1818.         pop di
  1819.         mov si, bx
  1820.  
  1821.         mov ax, 00h
  1822.         mov e_elem, ax        ; Zero
  1823.         mov c_elem, al        ;   values
  1824.         mov s_env, ax        ;     for use.
  1825.  
  1826.         lodsb            ; Get the delimiter.
  1827.         mov dl, al        ; Save it.
  1828.         push di
  1829.  
  1830.         call p_numb        ; Read number.
  1831.         mov e_elem, cx        ; Save element number.
  1832.  
  1833. element1:
  1834.         lodsb            ; Get a byte.
  1835.         cmp al, 0dh        ; Is it a return?
  1836.         jz element2        ; Yes Jump out.
  1837.  
  1838.         cmp al, dl        ; Is it a delimiter?
  1839.         jz element3        ; Yes. Jump out.
  1840.         mov c_elem, al        ; Save element delimiter.
  1841.         jmp element1
  1842.  
  1843. element2:
  1844.         pop di
  1845.         dec si
  1846.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  1847.         jmp nor_term        ; Exit.
  1848.  
  1849. element3:
  1850.         mov di, offset n_env    ; Store variable name here.
  1851.         call p_var        ; Read a string.
  1852.         mov s_env, cx        ; Save the size.
  1853.         pop di
  1854.  
  1855.         call loc_env        ; Get variable offset
  1856.         cmp f_env, 00h        ; Did we find the variable?
  1857.         jz element9
  1858.  
  1859.         dec si
  1860.         mov cs:[exit_code], 08h    ; Variable not found.
  1861.         jmp nor_term        ; Exit.        
  1862.  
  1863. element9:
  1864.         mov dx, e_elem        ; Element number.
  1865.         mov cx, 00h
  1866.  
  1867.         mov ax, o_env        ; Environment offset.
  1868.         mov bx, b_env        ; Environment base.
  1869.         push si
  1870.         push ds
  1871.         mov si, ax        ; Set for the
  1872.         mov ds, bx        ;   environment.
  1873.  
  1874.         cmp cx, dx        ; Is it the number 0.
  1875.         jz element11        ; Yes. Get it.
  1876.  
  1877. element10:
  1878.         lodsb            ; Get a byte.
  1879.         cmp al, 00h        ; At end of variable string?
  1880.         jz element12        ; Yes. Jump out.
  1881.  
  1882.         cmp al, cs:[c_elem]    ; Is it a delimiter?
  1883.         jnz element10        ; No. Loop.
  1884.  
  1885.         inc cx
  1886.         cmp cx, dx        ; Is it the right one.
  1887.         jnz element10        ; No. Loop.
  1888.  
  1889. element11:
  1890.         lodsb            ; Get a byte.
  1891.         cmp al, 00h        ; At end of variable string?
  1892.         jz element13        ; Yes. Jump out.
  1893.  
  1894.         cmp al, cs:[c_elem]    ; Is it a delimiter?
  1895.         jz element13        ; No. Loop.
  1896.  
  1897.         stosb            ; Save the byte.
  1898.         jmp element11
  1899.  
  1900. element12:
  1901.         pop ds
  1902.         pop si
  1903.         mov cs:[exit_code], 09h    ; Offset not valid.
  1904.         jmp nor_term        ; Exit.        
  1905.  
  1906. element13:
  1907.         pop ds
  1908.         pop si
  1909.  
  1910.         jmp get_data
  1911.  
  1912.  
  1913. ;        Handle %mid.
  1914. substr:
  1915.         push di
  1916.         push si
  1917.  
  1918.         mov di, si        ; Set destination.
  1919.         inc di
  1920.         mov si, offset l_mid    ; Set Source.
  1921.         mov cx, s_mid
  1922.         rep cmpsb        ; Is it %mid.
  1923.         jz get_substr        ; Yes.
  1924.  
  1925.         pop si
  1926.         push si
  1927.         mov di, si        ; Set destination.
  1928.         inc di
  1929.         mov si, offset u_mid    ; Set Source.
  1930.         mov cx, s_mid
  1931.         rep cmpsb        ; Is it %MID.
  1932.         jz get_substr        ; Yes.
  1933.  
  1934.         pop si
  1935.         pop di
  1936.         jmp locate        ; No. Jump out.
  1937.  
  1938. get_substr:
  1939.         mov bx, di
  1940.         pop si
  1941.         pop di
  1942.         mov si, bx
  1943.  
  1944.         mov ax, 00h
  1945.         mov y_mid, ax        ; Zero
  1946.         mov z_mid, ax        ;   values
  1947.         mov s_env, ax        ;     for use.
  1948.  
  1949.         lodsb            ; Get the delimiter.
  1950.         mov dl, al        ; Save it.
  1951.         push di
  1952.  
  1953.         mov di, offset n_env    ; Store variable name here.
  1954.         call p_var        ; Read a string.
  1955.         mov s_env, cx        ; Variable length.
  1956.  
  1957.         call p_numb        ; Read number.
  1958.         mov y_mid, cx        ; Save start postion.
  1959.  
  1960.         call p_numb        ; Read number.
  1961.         mov z_mid, cx        ; Save length to get.
  1962.         pop di
  1963.  
  1964.         call loc_env        ; Get variable offset
  1965.         cmp f_env, 00h        ; Did we find the variable?
  1966.         jz substr9
  1967.  
  1968.         mov cs:[exit_code], 08h    ; Variable not found.
  1969.         jmp nor_term        ; Exit.        
  1970.  
  1971. substr9:
  1972.         mov cx, z_mid        ; Length of substr.
  1973.         cmp cx, 00h        ; If not zero.
  1974.         jnz substr10
  1975.  
  1976.         mov cx, 0ffh        ; Make it large.
  1977. substr10:
  1978.         mov dx, y_mid        ; Starting position.
  1979.         cmp dx, 00h        ; If not zero.
  1980.         jnz substr11
  1981.  
  1982.         add dx, 01h        ; Make it one.
  1983. substr11:
  1984.         mov ax, o_env        ; Get env. variable offset.
  1985.         mov bx, ax        ; Add starting
  1986.         add bx, dx        ;   position.
  1987.  
  1988.         mov dx, b_env        ; Get env. base address.
  1989.         push si    
  1990.         push ds
  1991.         mov si, ax
  1992.         mov ds, dx
  1993.  
  1994. substr12:
  1995.         lodsb            ; Get a byte.
  1996.         cmp al, 00h        ; At end of variable data?
  1997.         jz substr13
  1998.  
  1999.         cmp si, bx        ; At starting position?
  2000.         jz substr14
  2001.         jmp substr12
  2002.  
  2003. substr13:
  2004.         pop ds
  2005.         pop si
  2006.         mov cs:[exit_code], 09h    ; Offset not valid.
  2007.         jmp nor_term        ; Exit.        
  2008.  
  2009. substr14:
  2010.         dec si
  2011.  
  2012. substr15:
  2013.         lodsb            ; Get a byte.
  2014.         cmp al, 00h        ; At end of variable data?
  2015.         jz substr16
  2016.  
  2017.         cmp cx, 00h        ; At end of length?
  2018.         jz substr16
  2019.  
  2020.         stosb            ; Move the byte.
  2021.         dec cx            ; One less byte to check.
  2022.         jmp substr15
  2023.  
  2024. substr16:
  2025.         pop ds
  2026.         pop si
  2027.  
  2028.         jmp get_data
  2029.  
  2030.  
  2031. ;        Handle %loc.
  2032. locate:
  2033.         push di
  2034.         push si
  2035.  
  2036.         mov di, si        ; Set destination.
  2037.         inc di
  2038.         mov si, offset l_loc    ; Set Source.
  2039.         mov cx, s_loc
  2040.         rep cmpsb        ; Is it %loc.
  2041.         jz get_locate        ; Yes.
  2042.  
  2043.         pop si
  2044.         push si
  2045.         mov di, si        ; Set destination.
  2046.         inc di
  2047.         mov si, offset u_loc    ; Set Source.
  2048.         mov cx, s_loc
  2049.         rep cmpsb        ; Is it %LOC.
  2050.         jz get_locate        ; Yes.
  2051.  
  2052.         pop si
  2053.         pop di
  2054.         jmp length0        ; No. Jump out.
  2055.  
  2056. get_locate:
  2057.         mov bx, di
  2058.         pop si
  2059.         pop di
  2060.         mov si, bx
  2061.  
  2062.         mov ax, 00h
  2063.         mov e_loc, ax        ; Zero
  2064.         mov s_env, ax        ;   values
  2065.         mov w_mid, ax        ;     for use.
  2066.  
  2067.         lodsb            ; Get the delimiter.
  2068.         mov dl, al        ; Save it.
  2069.         push di
  2070.  
  2071.         call p_numb        ; Read number.
  2072.         mov e_loc, cx        ; Save starting position.
  2073.  
  2074.         mov di, offset n_env    ; Store variable name here.
  2075.         call p_var        ; Read a string.
  2076.         mov s_env, cx        ; Variable length.
  2077.  
  2078.         mov di, offset x_mid    ; Store search string.
  2079.         call p_str        ; Read a string.
  2080.         mov w_mid, cx        ; Variable length.
  2081.         pop di
  2082.  
  2083.         call loc_env        ; Get variable offset
  2084.         cmp f_env, 00h        ; Did we find the variable?
  2085.         jz locate9
  2086.  
  2087.         mov cs:[exit_code], 08h    ; Variable not found.
  2088.         jmp nor_term        ; Exit.        
  2089.  
  2090. locate9:
  2091.         mov dx, e_loc        ; Starting position.
  2092.         cmp dx, 00h        ; If not zero.
  2093.         jnz locate10
  2094.  
  2095.         add dx, 01h        ; Make it one.
  2096. locate10:
  2097.         mov ax, o_env        ; Get env. variable offset.
  2098.         mov bx, ax        ; Add starting
  2099.         add bx, dx        ;   position.
  2100.  
  2101.         mov dx, b_env        ; Get env. base address.
  2102.         push si    
  2103.         push ds
  2104.         mov si, ax
  2105.         mov ds, dx
  2106.  
  2107. locate11:
  2108.         lodsb            ; Get a byte.
  2109.         cmp al, 00h        ; At end of variable data?
  2110.         jz locate12
  2111.  
  2112.         cmp si, bx        ; At starting position?
  2113.         jz locate13
  2114.         jmp locate11
  2115.  
  2116. locate12:
  2117.         pop ds
  2118.         pop si
  2119.         mov ax, 00h        ; Set for not found.
  2120.         jmp locate17
  2121.  
  2122. locate13:
  2123.         dec si
  2124.         push di
  2125.  
  2126. locate14:
  2127.         mov al, [si]        ; Get a test byte.
  2128.         cmp al, 00h        ; At end of variable data?
  2129.         jz locate15
  2130.  
  2131.         push si
  2132.  
  2133.         mov di, offset cs:[x_mid] ; Set destination.
  2134.         mov cx, cs:[w_mid]    ; Set Length.
  2135.         rep cmpsb        ; Is it the string.
  2136.         jz locate16        ; Yes. Jump out.
  2137.  
  2138.         pop si            ; Get offset back.
  2139.         inc si            ; Move on a byte.
  2140.         jmp locate14
  2141.  
  2142. locate15:
  2143.         pop di
  2144.         jmp locate12
  2145.  
  2146.  
  2147. locate16:
  2148.         mov ax, si        ; Save the offset
  2149.         pop si
  2150.         pop di
  2151.  
  2152.         pop ds
  2153.         pop si
  2154.  
  2155.         mov bx, o_env        ; Subtract env data
  2156.         sub ax, bx        ;   start from current location.
  2157.         mov bx, w_mid        ; Subtract
  2158.         sub ax, bx        ;   search length.
  2159.         inc ax
  2160.  
  2161. locate17:
  2162.         call dec_str
  2163.  
  2164.         jmp get_data
  2165.  
  2166.  
  2167. ;        Handle %len.
  2168. length0:
  2169.         push di
  2170.         push si
  2171.  
  2172.         mov di, si        ; Set destination.
  2173.         inc di
  2174.         mov si, offset l_len    ; Set Source.
  2175.         mov cx, s_len
  2176.         rep cmpsb        ; Is it %len.
  2177.         jz get_length        ; Yes.
  2178.  
  2179.         pop si
  2180.         push si
  2181.         mov di, si        ; Set destination.
  2182.         inc di
  2183.         mov si, offset u_len    ; Set Source.
  2184.         mov cx, s_len
  2185.         rep cmpsb        ; Is it %LEN.
  2186.         jz get_length        ; Yes.
  2187.  
  2188.         pop si
  2189.         pop di
  2190.         jmp sum_var        ; No. Jump out.
  2191.  
  2192. get_length:
  2193.         mov bx, di
  2194.         pop si
  2195.         pop di
  2196.         mov si, bx
  2197.  
  2198.         mov ax, 00h
  2199.         mov s_env, ax        ; Zero for use.
  2200.  
  2201.         lodsb            ; Get the delimiter.
  2202.         mov dl, al        ; Save it.
  2203.         push di
  2204.  
  2205.         mov di, offset n_env    ; Store variable name here.
  2206.         call p_var        ; Read a string.
  2207.         mov s_env, cx        ; Variable length.
  2208.         pop di
  2209.  
  2210.         call loc_env        ; Get variable offset
  2211.         cmp f_env, 00h        ; Did we find the variable?
  2212.         jz length9
  2213.  
  2214.         mov cs:[exit_code], 08h    ; Variable not found.
  2215.         jmp nor_term        ; Exit.        
  2216.  
  2217. length9:
  2218.         mov ax, o_env        ; Get env. variable offset.
  2219.         mov dx, b_env        ; Get env. base address.
  2220.         mov cx, 00h
  2221.  
  2222.         push si    
  2223.         push ds
  2224.         mov si, ax
  2225.         mov ds, dx
  2226.  
  2227. length10:
  2228.         lodsb            ; Get a byte.
  2229.         cmp al, 00h        ; At end of variable data?
  2230.         jz length11
  2231.  
  2232.         inc cx            ; Count the bytes.
  2233.         jmp length10
  2234.  
  2235. length11:
  2236.         pop ds
  2237.         pop si
  2238.  
  2239.         mov ax, cx        ; Save length.
  2240.         call dec_str
  2241.  
  2242.         jmp get_data
  2243.  
  2244.  
  2245. ;        Handle %sum.
  2246. sum_var:
  2247.         push di
  2248.         push si
  2249.  
  2250.         mov di, si        ; Set destination.
  2251.         inc di
  2252.         mov si, offset l_sum    ; Set Source.
  2253.         mov cx, s_sum
  2254.         rep cmpsb        ; Is it %sum.
  2255.         jz get_sum_var        ; Yes.
  2256.  
  2257.         pop si
  2258.         push si
  2259.         mov di, si        ; Set destination.
  2260.         inc di
  2261.         mov si, offset u_sum    ; Set Source.
  2262.         mov cx, s_sum
  2263.         rep cmpsb        ; Is it %SUM.
  2264.         jz get_sum_var        ; Yes.
  2265.  
  2266.         pop si
  2267.         pop di
  2268.         jmp get_next        ; No. Jump out.
  2269.  
  2270. get_sum_var:
  2271.         mov bx, di
  2272.         pop si
  2273.         pop di
  2274.         mov si, bx
  2275.  
  2276.         mov ax, 00h
  2277.         mov s_env, ax        ; Zero for use.
  2278.  
  2279.         lodsb            ; Get the delimiter.
  2280.         mov dl, al        ; Save it.
  2281.         push di
  2282.  
  2283.         mov di, offset n_env    ; Store variable name here.
  2284.         call p_var        ; Read a string.
  2285.         mov s_env, cx        ; Variable length.
  2286.  
  2287.         mov nmb_tst, 0ffh    ; Set to test sign.
  2288.         call p_numb        ; Read number.
  2289.         mov v_sum, cx        ; Save sum number.
  2290.         mov nmb_tst, 00h    ; Remove test for sign.
  2291.         pop di
  2292.  
  2293.         call loc_env        ; Get variable offset
  2294.         cmp f_env, 00h        ; Did we find the variable?
  2295.         jz sum_var9
  2296.  
  2297.         mov cs:[exit_code], 08h    ; Variable not found.
  2298.         jmp nor_term        ; Exit.        
  2299.  
  2300. sum_var9:
  2301.         mov ax, o_env        ; Get env. variable offset.
  2302.         mov dx, b_env        ; Get env. base address.
  2303.         mov cx, 00h
  2304.         mov f_sum, "+"        ; Set for add.
  2305.  
  2306.         push si    
  2307.         push ds
  2308.         mov si, ax
  2309.         mov ds, dx
  2310.  
  2311. sum_var10:
  2312.         lodsb            ; Get a byte.
  2313.         cmp al, " "        ; Leading space.
  2314.         jz sum_var10        ; Then remove it.
  2315.  
  2316.         cmp al, 09h        ; Leading tab.
  2317.         jz sum_var10        ; Then remove it.
  2318.  
  2319.         cmp al, "+"        ; Is it an add.
  2320.         jz sum_var12
  2321.  
  2322.         cmp al, "-"        ; Is it an minus.
  2323.         jnz sum_var11
  2324.         mov cs:[f_sum], "-"
  2325.         jmp sum_var12
  2326.  
  2327. sum_var11:
  2328.         dec si
  2329. sum_var12:
  2330.         lodsb            ; Get a byte.
  2331.         cmp al, "9"        ; Is
  2332.         jg sum_var14        ;   it
  2333.         cmp al, "0"        ;     numeric?
  2334.         jb sum_var14        ; No. Then error.
  2335.  
  2336.         mov ah, 00h
  2337.         sub al, 30h        ; Make it binary.
  2338.         mov bx, ax        ; Save next digit.
  2339.         mov ax, cx        ; Get the number.
  2340.         push dx
  2341.         push bx
  2342.         mov bx, 0ah        ; Multiply 
  2343.         mul bx            ;   by ten.
  2344.         pop bx
  2345.         pop dx
  2346.         add ax, bx        ; Add next digit.
  2347.         mov cx, ax        ; Save number.
  2348.         jmp sum_var12
  2349.  
  2350. sum_var13:
  2351.         lodsb            ; Get a byte.
  2352. sum_var14:
  2353.         cmp al, 00h        ; At end of variable data?
  2354.         jz sum_var15
  2355.  
  2356.         cmp al, " "        ; Leading space.
  2357.         jz sum_var13        ; Then remove it.
  2358.  
  2359.         cmp al, 09h        ; Leading tab.
  2360.         jz sum_var13        ; Then remove it.
  2361.  
  2362.         pop di
  2363.         dec si
  2364.         mov cs:[exit_code], 07h    ; Argument not a number.
  2365.         jmp nor_term        ; Exit.
  2366.  
  2367. sum_var15:        
  2368.         pop ds
  2369.         pop si
  2370.  
  2371.         mov ax, cx        ; Value of the variable.
  2372.         mov cx, v_sum        ; Value to add.
  2373.  
  2374.         cmp nmb_sgn, "+"    ; Is the number positive?
  2375.         jz sum_var16
  2376.  
  2377.         cmp f_sum, "+"        ; Is the variable positive?
  2378.         jz sum_var17
  2379.  
  2380.         push ax
  2381.         mov al, "-"        ; Write out
  2382.         stosb            ;   the sign.
  2383.         pop ax
  2384.         jmp sum_var21
  2385.  
  2386. sum_var16:
  2387.         cmp f_sum, "+"        ; Is the variable positive?
  2388.         jz sum_var21
  2389.  
  2390. sum_var17:
  2391.         cmp ax, cx        ; Is the number gt the variable?
  2392.         jge sum_var20
  2393.  
  2394.         mov dx, cx        ; Then
  2395.         mov cx, ax        ;   switch
  2396.         mov ax, dx        ;     them arround.
  2397.  
  2398.         cmp nmb_sgn, "+"    ; Is the number positive?
  2399.         jz sum_var19
  2400. sum_var18:
  2401.         push ax
  2402.         mov al, "-"        ; Write out
  2403.         stosb            ;   the sign.
  2404.         pop ax                
  2405.  
  2406. sum_var19:
  2407.         sub ax, cx        ; Subtract the difference.
  2408.         jmp sum_var22
  2409.  
  2410. sum_var20:
  2411.         cmp f_sum, "+"        ; Is the variable positive?
  2412.         jz sum_var19        
  2413.  
  2414.         cmp ax, cx        ; No sign if equal.
  2415.         jz sum_var19
  2416.         jmp sum_var18
  2417.  
  2418. sum_var21:
  2419.         add ax, cx        ; Add the number to variable.
  2420.  
  2421. sum_var22:
  2422.         call dec_str        ; Convert to decimal string.
  2423.  
  2424.         jmp get_data
  2425.  
  2426.  
  2427. ;        parse a number from the command line
  2428. p_numb:
  2429.         lodsb            ; Get a byte.
  2430.         cmp al, " "        ; Leading space.
  2431.         jz p_numb        ; Then remove it.
  2432.  
  2433.         cmp al, 09h        ; Leading tab.
  2434.         jz p_numb        ; Then remove it.
  2435.  
  2436.         mov cx, 00h
  2437.         cmp nmb_tst, 00h    ; Do we test for sign.
  2438.         jz p_numb1
  2439.  
  2440.         mov nmb_sgn, "+"    ; Set initial sign.
  2441.         cmp al, "+"        ; Is it an add.
  2442.         jz p_numb2
  2443.  
  2444.         cmp al, "-"        ; Is it an minus.
  2445.         jnz p_numb1
  2446.         mov nmb_sgn, "-"    ; Save the sign.
  2447.         jmp p_numb2
  2448.  
  2449. p_numb1:
  2450.         dec si
  2451.  
  2452. ;        The maximum element is 255.
  2453. p_numb2:
  2454.         lodsb            ; Get a byte.
  2455.         cmp al, "9"        ; Is
  2456.         jg p_numb4        ;   it
  2457.         cmp al, "0"        ;     numeric?
  2458.         jb p_numb4        ; No. Then error.
  2459.  
  2460.         mov ah, 00h
  2461.         sub al, 30h        ; Make it binary.
  2462.         mov bx, ax        ; Save next digit.
  2463.         mov ax, cx        ; Get the number.
  2464.         push dx
  2465.         push bx
  2466.         mov bx, 0ah        ; Multiply 
  2467.         mul bx            ;   by ten.
  2468.         pop bx
  2469.         pop dx
  2470.         add ax, bx        ; Add next digit.
  2471.         mov cx, ax        ; Save number.
  2472.         jmp p_numb2
  2473.  
  2474. p_numb3:
  2475.         lodsb            ; Get a byte.
  2476. p_numb4:
  2477.         cmp al, 0dh        ; Is it the end?
  2478.         jz p_numb5        ; Yes Jump out.
  2479.  
  2480.         cmp al, dl        ; Digits over?.
  2481.         jz p_numb6        ; Yes Jump out.
  2482.  
  2483.         cmp al, " "        ; Leading space.
  2484.         jz p_numb3        ; Then remove it.
  2485.  
  2486.         cmp al, 09h        ; Leading tab.
  2487.         jz p_numb3        ; Then remove it.
  2488.  
  2489.         pop di
  2490.         dec si
  2491.         mov cs:[exit_code], 07h    ; Argument not a number.
  2492.         jmp nor_term        ; Exit.
  2493.  
  2494. p_numb5:
  2495.         pop di
  2496.         dec si
  2497.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  2498.         jmp nor_term        ; Exit.
  2499.  
  2500. p_numb6:
  2501.         ret
  2502.  
  2503.  
  2504. ;        parse the variable from the command line
  2505. p_str:
  2506.         mov cx, 00h
  2507.  
  2508. p_str1:
  2509.         lodsb            ; Get a byte.
  2510.         cmp al, 0dh        ; Is it the end?
  2511.         jz p_numb5        ; Yes Jump out.
  2512.  
  2513.         cmp al, dl        ; Is it a delimiter?
  2514.         jz p_str3        ; Yes. Jump out.
  2515.  
  2516. p_str2:
  2517.         stosb            ; Save it.
  2518.         inc cx            ; Increment the count.
  2519.         jmp p_str1
  2520.  
  2521. p_str3:
  2522.         ret
  2523.  
  2524.  
  2525. ;        parse a string from the command line
  2526. ;        and convert lower to upper
  2527. p_var:
  2528.         lodsb            ; Get a byte.
  2529.         cmp al, " "        ; Leading space.
  2530.         jz p_var        ; Then remove it.
  2531.  
  2532.         cmp al, 09h        ; Leading tab.
  2533.         jz p_var        ; Then remove it.
  2534.  
  2535.         dec si
  2536.         mov cx, 00h
  2537.  
  2538. p_var1:
  2539.         lodsb            ; Get a byte.
  2540.         cmp al, 0dh        ; Is it the end?
  2541.         jz p_numb5        ; Yes Jump out.
  2542.  
  2543.         cmp al, dl        ; Is it a delimiter?
  2544.         jz p_var2        ; Yes. Jump out.
  2545.  
  2546.         cmp al, " "        ; Leading space.
  2547.         jz p_var1        ; Then remove it.
  2548.  
  2549.         cmp al, 09h        ; Leading tab.
  2550.         jz p_var1        ; Then remove it.
  2551.  
  2552.         call uppercase        ; Convert to uppercase.
  2553.         stosb            ; Save it.
  2554.         inc cx            ; Increment the count.
  2555.         jmp p_var1
  2556.  
  2557. p_var2:
  2558.         ret
  2559.  
  2560.  
  2561. ;        End of data now finish it.
  2562. data_end:
  2563.         mov al, 00h        ; Save
  2564.         stosb            ;   two
  2565.         stosb            ;     nulls.
  2566.         mov ax, di        ; Get the offset.
  2567.         mov bx, offset d_env_var ; The beginng of the variable.
  2568.         sub ax, bx        ; Get the data length.
  2569.         mov s_data, ax        ; And save it.
  2570.  
  2571.         cmp v_rep, 0ffh        ; Are we going to replace.
  2572.         jz get_psp        ; Yes. Jump.
  2573.         cmp v_rce, 00h        ; Are we going to do root.
  2574.         jz get_psp        ; No.  Jump over.
  2575.         jmp set_root
  2576.  
  2577. get_psp:
  2578.         push ds            ; Save the segment base.
  2579.  
  2580. ;        PSP of program.
  2581.         mov si, 16h
  2582.         mov ax, [si]
  2583.  
  2584. ;        Parent PSP Segment of program.
  2585.         mov ds, ax        ; Set the data segment.
  2586.         mov si, 16h        ; Parent PSP Segment.
  2587.         mov ax, [si]
  2588.  
  2589. ;        Parent PSP Segment of command.com.
  2590.         mov ds, ax        ; Set the data segment.
  2591.         mov si, 16h        ; Parent PSP Segment.
  2592.         mov ax, [si]
  2593.         mov cs:[cpsp], ax
  2594.  
  2595. ;        Check if the Environment Address is usable.
  2596.         mov si, 2ch        ; Environment space
  2597.         mov bx, [si]        ;   of command.com.
  2598.         cmp bx, 00h        ; If it's zero we
  2599.         jz zero_add        ;   do a long search.
  2600.  
  2601.         sub bx, 01h        ; We will have to back
  2602.         mov ax, bx        ;   up to env. definition.
  2603.  
  2604. zero_add:
  2605. ;        Segment where the environment space is.
  2606.         mov ds, ax
  2607.         mov si, 00h
  2608.  
  2609. get4d:
  2610. ;        Look for 4dh on segment boundary.
  2611.         mov al, [si]
  2612.         cmp al, 4dh
  2613.         jz got4d
  2614.  
  2615. inc_seg:
  2616.         mov ax, si        ; Increment
  2617.         add ax, 10h        ;   to the next
  2618.         mov si, ax        ;      segment boundary.
  2619.         jmp get4d
  2620.  
  2621. got4d:
  2622.         mov ax, 1[si]        ; Get the psp.
  2623.         cmp cs:[cpsp], ax    ; Is it the same as cpsp?
  2624.         jnz inc_seg        ; No.  Jump out.
  2625.  
  2626.         mov ah, 00h
  2627.         mov al, 3[si]        ; Get the number of segments.
  2628.         mov bx, 10h
  2629.         mul bx            ; Get the number of bytes.
  2630.         mov cs:[env_siz], ax    ; Save it.
  2631.  
  2632.         mov ax, si        ; Increment
  2633.         add ax, 10h        ;   to the environment
  2634.         mov si, ax        ;      segment boundary.
  2635.         mov cs:[env_off], ax    ; Save it.
  2636.  
  2637. ;        Just a double check for environment space.
  2638. ;        Check for PATH= or PROMPT= or COMPEC= or SETENV=.
  2639.         mov ax, ds        ; Get the data segment
  2640.         mov es, ax        ; and put it in extra segment.
  2641.         mov di, si        ; This is our destination.
  2642.  
  2643.         pop ds            ; Restore the data segment.
  2644.         mov si, offset d_path    ; Check
  2645.         mov cx, s_path        ;   for
  2646.         rep cmpsb        ;     PATH=.
  2647.         jz got_env
  2648.  
  2649.         mov di, env_off        ; Restore the destination.
  2650.         mov si, offset d_prompt    ; Check
  2651.         mov cx, s_prompt    ;   for
  2652.         rep cmpsb        ;     PROMPT=.
  2653.         jz got_env
  2654.  
  2655.         mov di, env_off        ; Restore the destination.
  2656.         mov si, offset d_comspec ;Check
  2657.         mov cx, s_comspec    ;    for
  2658.         rep cmpsb        ;      COMSPEC=.
  2659.         jz got_env
  2660.  
  2661.         mov di, env_off        ; Restore the destination.
  2662.         mov si, offset d_setenv    ; Check
  2663.         mov cx, s_setenv    ;   for
  2664.         rep cmpsb        ;     SETENV=.
  2665.         jz got_env
  2666.  
  2667.         push ds            ; Save the data segment.
  2668.         mov ax, es        ; Get the
  2669.         mov ds, ax        ;   data segment
  2670.         mov si, cs:[env_off]    ;     and source
  2671.         jmp get4d        ;       to scan some more.
  2672.  
  2673. got_env:
  2674.         push ds            ; Save the data segment.
  2675.         mov ax, es        ; Get the
  2676.         mov ds, ax        ;   data segment
  2677.         mov si, cs:[env_off]    ;     and source.
  2678.  
  2679.         mov di, offset cs:[d_env_var]    ; First character
  2680.         mov bl, cs:[di]        ;   of environment variable.
  2681.         jmp zero1
  2682. ;        Scan through environment for the end,
  2683. ;        we need two null bytes.
  2684. loop:
  2685.         lodsb            ; Get a byte.
  2686.         cmp al, 00h        ; Is it null?
  2687.         jz zero1        ; Yes. Got first null.
  2688.         jmp loop        ; Keep looking.
  2689.  
  2690. ;        Is the variable there?
  2691. zero1:
  2692.         lodsb            ; Get a byte.
  2693.         cmp al, 00h        ; Is it zero?
  2694.         jz write_near        ; Yes.  Jump out.
  2695.         cmp al, bl        ; Is it the env. variable?
  2696.         jnz loop        ; No.  Jump out.
  2697.  
  2698.         dec si            ; We are N+1.
  2699.         mov ax, ds        ; Get the data segment
  2700.         mov es, ax        ; and put it in extra segment.
  2701.         mov di, si        ; This is our destination.
  2702.  
  2703.         mov dx, si        ; Save the address of env. var.
  2704.         pop ds            ; Restore the data segment.
  2705.         mov si, offset d_env_var ; Set the source.
  2706.         mov cx, s_env_var    ; Length of variable.
  2707.         rep cmpsb        ; Does it exist?
  2708.         jz update
  2709.  
  2710.         push ds            ; Save the data segment.
  2711.         mov ax, es        ; Get the extra segment.
  2712.         mov ds, ax        ; and put it in data segment.
  2713.         mov si, di        ; Setup the source.
  2714.         jmp loop
  2715.  
  2716. write_near:
  2717.         jmp write
  2718. subst_near:
  2719.         jmp substitute
  2720. change_near:
  2721.         jmp change
  2722.  
  2723.  
  2724. ;        The environment variable is there.
  2725. ;        Now update the environment variable.
  2726. update:
  2727.         cmp cs:[v_rep], 0ffh    ; Do we replace?
  2728.         jz subst_near        ; Yes. Go there.
  2729.  
  2730.         cmp cs:[v_chgup], 0ffh    ; Do we upper case string?
  2731.         jz change_near        ; Yes. Go there.
  2732.  
  2733.         cmp cs:[v_chglo], 0ffh    ; Do we lower case string?
  2734.         jz change_near        ; Yes. Go there.
  2735.  
  2736. update0:
  2737.         push ds            ; Save the data segment.
  2738.         mov ax, es        ; Get the extra segment.
  2739.         mov ds, ax        ; and put it in data segment.
  2740.         mov di, dx        ; This is our destination.
  2741.         mov si, di        ; Setup the source.
  2742.         
  2743. update1:
  2744.         lodsb            ; Skip
  2745.         cmp al, 00h        ;   over
  2746.         jnz update1        ;     the variable.
  2747.  
  2748.         lodsb            ; Look ahead to see
  2749.         dec si            ;   if the next byte
  2750.         cmp al, 00h        ;     is zero if not
  2751.         jz update3        ;       compress the data.
  2752.  
  2753. update2:
  2754.         lodsb            ; Compress
  2755.         stosb            ;   the data
  2756.         cmp al, 00h        ;     for a
  2757.         jnz update2        ;       variable.
  2758.  
  2759.         lodsb            ; Get a byte.
  2760.         dec si
  2761.         cmp al, 00h        ; Is it zero?
  2762.         jnz update2        ; No.  Get next.
  2763.  
  2764. update3:
  2765.         mov al, cs:[exit_code]
  2766.         cmp al, 05h
  2767.         jg update4
  2768.         mov cs:[exit_code], 05h    ; Environment variable updated.
  2769. update4:
  2770.         mov cx, cs:[s_data]    ; Length of data.
  2771.         mov dx, cs:[s_env_var]    ; Length of name.
  2772.         sub cx, dx
  2773.         sub cx, 02h        ; Minus 2 zeroes.
  2774.         cmp cx, 00h        ; Is it just the name.
  2775.         jnz write1        ; No. Jump out.
  2776.  
  2777.         mov cx, si        ; End of old environment.
  2778.         mov dx, di        ; Current position.
  2779.         sub cx, dx
  2780.         mov al, 00h        ; Zero
  2781.         rep stosb        ;  the rest.
  2782.         mov cs:[exit_code], 02h    ; Environment variable erased.
  2783.         jmp nor_term
  2784.  
  2785. ;        The environment variable isn't there.
  2786. ;        Now move the data into place.
  2787. write:
  2788.         mov ax, ds        ; Get the data segment
  2789.         mov es, ax        ; and put it in extra segment.
  2790.         dec si            ; We are N+1.
  2791.         mov di, si        ; This is our destination.
  2792.  
  2793. write1:
  2794.         mov cx, cs:[s_data]    ; Environment variable & data.
  2795.         dec cx            ; No
  2796.         dec cx            ;   nulls.
  2797.         mov ax, cs:[s_env_var]    ; Environment variable size.
  2798.         cmp ax, cx        ; Same size.
  2799.         jne write2        ; No. Jump out.
  2800.         mov cs:[exit_code], 08h    ; Environment variable not found.
  2801.         jmp nor_term
  2802.  
  2803. write2:
  2804.         pop ds            ; Restore the data segment.
  2805.         mov si, offset d_env_var ; Set the source.
  2806.         mov cx, s_data        ; Set the length.
  2807. write3:
  2808.         mov ah, es:[di]        ; Get destination byte.
  2809. write4:
  2810.         cmp ah, 00h        ; Is it a zero?
  2811.         jnz not_zero        ; No.  Jump out.
  2812.         lodsb            ; Get byte.
  2813.         stosb            ; Save byte.
  2814.         loop write3        ; Loop.
  2815.  
  2816. ;        Exit the program.
  2817. nor_term:
  2818.         mov al, cs:[exit_code]    ; Set termination code.
  2819.         mov ah, 4ch        ; Termination.
  2820.         int 21h
  2821.  
  2822. not_zero:
  2823.         mov ax, di        ; Get the current offset.
  2824.         mov bx, env_off        ; Get environment start.
  2825.         sub ax, bx        ; Subtract the start of env.
  2826.         mov bx, env_siz        ; Get environment size.
  2827.         cmp ax, bx        ; Greater the environment size.
  2828.         jge reset        ; Yes.  Jump.
  2829.         mov ah, 00h        ; Make it zero.
  2830.         mov al, exit_code    ; Get exit code.
  2831.         cmp al, 05h        ; If update then do not
  2832.         jmp write4        ;   reduce the error code.
  2833. ;        jge write4        ;   reduce the error code.
  2834. ;        mov exit_code, 04h    ; Environment space over written.
  2835. ;        jmp write4        ;   and redo.
  2836.  
  2837. reset:
  2838.         dec di
  2839.         dec di
  2840.         mov al, 00h        ; Put zero back.
  2841.         stosb
  2842.         stosb
  2843.         mov exit_code, 10h    ; Set code for out of env.,
  2844.         jmp nor_term        ;   and terminate.
  2845.  
  2846. ;        Replace old text with new text.
  2847. substitute:
  2848.         push dx
  2849.         push ds
  2850.         push es
  2851.         push si
  2852.         push di
  2853.  
  2854.         mov ax, es        ; Switch
  2855.         mov bx, ds        ;   the
  2856.         mov es, bx        ;     segments
  2857.         mov ds, ax        ;       around.
  2858.  
  2859.         mov ax, di        ; Switch
  2860.         mov di, si        ;   the
  2861.         mov si, ax        ;     registrars.
  2862.  
  2863.         mov bx, offset d_arg1    ; Get first byte
  2864.         mov dl, cs:[bx]        ;   of old data.
  2865. subst1:
  2866.         lodsb            ; Get byte.
  2867.         cmp al, 00h        ; End of variable space.
  2868.         jz subst5        ; Yes. Jump out.
  2869.  
  2870.         cmp al, dl        ; First byte of data?
  2871.         jz subst3        ; Yes. Jump out
  2872. subst2:
  2873.         stosb            ; Save byte.
  2874.         jmp subst1
  2875.  
  2876. ;        Test for old text.
  2877. subst3:
  2878.         push ds
  2879.         push es
  2880.         push di
  2881.         push si
  2882.  
  2883.         mov ax, es        ; Switch
  2884.         mov bx, ds        ;   the
  2885.         mov es, bx        ;     segments
  2886.         mov ds, ax        ;       around.
  2887.  
  2888.         mov di, si
  2889.         dec di            ; Data N+1.
  2890.         mov si, offset d_arg1    ; Old data value.
  2891.         mov cx, cs:[s_arg1]    ; Old data size.
  2892.         rep cmpsb
  2893.         jz subst4
  2894.  
  2895.         mov al, dl        ; Get byte back.
  2896.         pop si
  2897.         pop di
  2898.         pop es
  2899.         pop ds
  2900.         jmp subst2
  2901.  
  2902. ;        Put in new text.
  2903. subst4:
  2904.         pop si
  2905.         pop di
  2906.         mov ax, ds
  2907.         mov es, ax
  2908.  
  2909.         mov bx, si
  2910.         dec si            ; Data N+1.
  2911.         push si
  2912.  
  2913.         mov si, offset d_arg2    ; New data value.
  2914.         mov cx, s_arg2        ; New data size.
  2915.         rep movsb
  2916.  
  2917.         pop si
  2918.         mov cx, si
  2919.         mov ax, s_arg1        ; Add size of
  2920.         add cx, ax        ;   new value.
  2921.         mov si, cx        ; Advance the size.
  2922.  
  2923.         pop es
  2924.         pop ds
  2925.         jmp subst1
  2926.  
  2927. subst5:
  2928.         stosb            ; Save two
  2929.         stosb            ;   nulls.
  2930.         pop di
  2931.         pop si
  2932.         pop es
  2933.         pop ds
  2934.  
  2935.         mov v_rep, 00h        ; Turn off replace.
  2936.         push si
  2937.         push di
  2938.  
  2939.         mov si, offset d_env_var
  2940.         mov cx, 00h
  2941. subst6:
  2942.         lodsb            ; Get
  2943.         inc cx            ;   the
  2944.         cmp al, 00h        ;     size.
  2945.         jnz subst6
  2946.  
  2947.         inc cx
  2948.         mov s_data, cx        ; Save the size.
  2949.  
  2950.         pop di
  2951.         pop si
  2952.         pop dx
  2953.         jmp update0
  2954.  
  2955. ;        Replace old text with new text, for case.
  2956. change:
  2957.         mov ax, es        ; Switch
  2958.         mov ds, ax        ;   the
  2959.         mov si, di        ;     registers.
  2960.  
  2961. change1:
  2962.         lodsb            ; Get a byte.
  2963.         cmp al, 00h        ; Is it null?
  2964.         jz change9        ; Yes. End of variable.
  2965.  
  2966.         cmp cs:[v_chgup], 0ffh    ; Do we upper case string?
  2967.         jnz change2
  2968.         call uppercase        ; Convert to uppercase.
  2969.         jmp change3
  2970.  
  2971. change2:
  2972.         cmp cs:[v_chglo], 0ffh    ; Do we lower case string?
  2973.         jnz change3
  2974.         call lowercase        ; Convert to lowercase.
  2975.  
  2976. change3:
  2977.         stosb            ; Replace it.
  2978.         jmp change1        ; Next byte.
  2979.  
  2980. change9:
  2981.         mov cs:[exit_code], 05h    ; Environment variable updated.
  2982.         jmp nor_term
  2983.  
  2984.  
  2985. ;        Root environment.
  2986. set_root:
  2987.         mov si, offset set    ; Move in the 'set='
  2988.         mov di, offset d_rce    ;   into the data area.
  2989.         inc di            ; Leave room for size.
  2990.         mov cx, 04h
  2991.         rep movsb        ; Move string.
  2992.  
  2993.         mov si, offset d_env_var ; Environment data.
  2994.         mov cx, s_data
  2995.         dec cx            ; Ignore the
  2996.         dec cx            ;   two nulls.
  2997.         rep movsb        ; Move string.
  2998.  
  2999.         mov al, 0dh        ; Put in the CR to terminate.
  3000.         stosb
  3001.         mov ax, s_data        ; Set the size and
  3002.         inc al            ;   add the
  3003.         inc al            ;     size for 'set='.
  3004.         mov byte ptr d_rce, al    ; Save the count.
  3005.  
  3006.         mov bx, offset lastloc+15 ; bx := program size
  3007.         mov cx, 04h        ;   in paragraphs.
  3008.         shr bx, cl
  3009.         mov ax, 4a00h        ; Deallocate unused memory.
  3010.         int 21h
  3011.  
  3012.         mov si, offset d_rce    ; Point at command.
  3013.         int 02eh        ; Execute the DOS command.
  3014.  
  3015.         mov ax, cs
  3016.         mov ss, ax
  3017.         mov ds, ax
  3018.         mov es, ax
  3019.         mov cs:[exit_code], 01h    ; Set code for environment
  3020.         jmp nor_term        ;   root set and terminate.
  3021.  
  3022. ;        convert a binary number to decimal string.
  3023. dec_str:
  3024.         mov    byte ptr dec_zfl, 0ffh    ; leading zero flag
  3025.         mov    bx, 10000
  3026.         call    dec_dig            ; get the 10000's digit
  3027.         mov    bx, 1000
  3028.         call    dec_dig            ; get the 1000's digit
  3029.         mov    bx, 100
  3030.         call    dec_dig            ; get the 100's digit
  3031.         mov    bx, 10
  3032.         call    dec_dig            ; get the 10's digit
  3033.         add    al, '0'            ; get the 1's digit
  3034.         jmp    dec_mov
  3035.  
  3036. dec_dig:
  3037.         mov    dx, 00h            ; clear remainder
  3038.         div    bx            ; divide ax by digit value
  3039.         add    al, '0'            ; convert to ascii digit
  3040.  
  3041.         cmp    byte ptr dec_zfl, 0ffh    ; suppress zero
  3042.         jne    dec_mov            ; no.  jump out
  3043.  
  3044.         cmp    al, '0'            ; if it a zero
  3045.         je    dec_nxt            ; yes.  jump out
  3046.         mov    byte ptr dec_zfl, 0h    ; set print zero
  3047.  
  3048. dec_mov:
  3049.         stosb                ; store the digit
  3050. dec_nxt:
  3051.         mov    ax, dx            ; setup for next digit
  3052.         ret
  3053.  
  3054.  
  3055. ;        Convert lowercase to uppercase.
  3056. uppercase:
  3057.         cmp al, "z"        ; Is
  3058.         jg not_lower1        ;   it
  3059.         cmp al, "a"        ;     lower
  3060.         jb not_lower1        ;       case?
  3061.         sub al, 20h        ; Make it upper case.
  3062. not_lower1:
  3063.         ret
  3064.  
  3065.  
  3066. ;        Convert uppercase to lowercase.
  3067. lowercase:
  3068.         cmp al, "Z"        ; Is
  3069.         jg not_upper1        ;   it
  3070.         cmp al, "A"        ;     upper
  3071.         jb not_upper1        ;       case?
  3072.         add al, 20h        ; Make it lower case.
  3073. not_upper1:
  3074.         ret
  3075.  
  3076.  
  3077. ;        copy environment variable data out.
  3078. copy_env:
  3079.         push ds
  3080.         push es
  3081.         push di
  3082.         push si
  3083.  
  3084.         mov ax, o_env        ; Get env. variable offset.
  3085.         mov si, ax
  3086.         mov ax, b_env        ; Get env. bas address.
  3087.  
  3088.         mov ds, ax        ; Set source.
  3089.         mov cx, 00h        ; Zero counter.
  3090.  
  3091. copy_env1:
  3092.         lodsb            ; Get a byte.
  3093.         cmp al, 00h        ; At end of variable data?
  3094.         jz copy_env2
  3095.  
  3096.         inc cx            ; Count the bytes.
  3097.         stosb            ; Save the byte.
  3098.         jmp copy_env1
  3099.  
  3100. copy_env2:
  3101.         pop si
  3102.         pop di
  3103.         pop es
  3104.         pop ds
  3105.         ret
  3106.  
  3107.  
  3108. ;    subroutine to find a variable in the local environment
  3109. loc_env:
  3110.         push ax
  3111.         push bx
  3112.         push cx
  3113.         push dx
  3114.         push si
  3115.         push di
  3116.         push es
  3117.         push ds
  3118.  
  3119.         mov al, 0ffh
  3120.         mov f_env, al        ; Initialize flag.
  3121.         mov ax, b_env        ; Get environment base address.
  3122.         cmp ax, 00h        ; Is it zero?
  3123.         jnz loc_env1        ; Yes Jump out.
  3124.  
  3125.         mov si, 2ch        ; Environment offset.
  3126.         mov ax, [si]        ; Get the address.
  3127.         mov b_env, ax        ; Save it.
  3128.  
  3129. loc_env1:
  3130.         mov bx, 00h        ; Offset of source.
  3131.         mov dx, offset n_env    ; Offset of destination.
  3132.  
  3133.         mov ax, b_env        ; Get environment base.
  3134.         mov ds, ax        ; Set environment base.
  3135. loc_env2:
  3136.         mov si, bx        ; Set source offset.
  3137.         mov di, dx        ; Point at the variable.
  3138.         mov cx, cs:[s_env]    ; Length of variable.
  3139.         rep cmpsb        ; Is it here.
  3140.         jz loc_env5
  3141.  
  3142.         mov si, bx        ; Backup over this variable.
  3143. loc_env3:
  3144.         lodsb            ; Search
  3145.         cmp al, 00h        ;  for end
  3146.         jnz loc_env3        ;    of varible.
  3147.  
  3148.         mov al, [si]        ; Are we at
  3149.         cmp al, 00h        ;   the end of
  3150.         jz loc_env9        ;     the environment?
  3151.  
  3152.         mov bx, si        ; Set for new variable.
  3153.         jmp loc_env2
  3154.  
  3155. loc_env5:
  3156.         mov al, [si]        ; We have the variable.
  3157.         cmp al, "="        ; Is it only a first part?
  3158.         jnz loc_env3        ; No. Look again.
  3159.  
  3160.         pop ds
  3161.         inc si            ; Skip equal sign.
  3162.         mov o_env, si        ; Set offset.
  3163.         mov al, 00h        ; Search success.
  3164.         mov f_env, al        ; Set it.
  3165.         push ds
  3166.  
  3167. loc_env9:
  3168.         pop ds
  3169.         pop es
  3170.         pop di
  3171.         pop si
  3172.         pop dx
  3173.         pop cx
  3174.         pop bx
  3175.         pop ax
  3176.         ret
  3177.  
  3178.  
  3179. ;        Generate a character if % is there.
  3180. make_char:
  3181.         cmp al, "%"        ; Is it percent.
  3182.         jnz make_char3
  3183.  
  3184.         lodsb            ; Get the delimiter.
  3185.         cmp al, "/"        ; Is it a /.
  3186.         jnz make_char2
  3187.  
  3188.         mov dl, al        ; Save it.
  3189.         push di
  3190.  
  3191.         call p_numb        ; Read number.
  3192.         mov n_chr, cx        ; Save element number.
  3193.  
  3194.         pop di
  3195.         cmp cx, 00h        ; Is it going to be a null.
  3196.         jz make_char2        ; No. Error.
  3197.  
  3198.         cmp cx, 0ffh        ; Is it valid?
  3199.         jg make_char3        ; Yes. Jump out.
  3200.  
  3201.         mov al, cl        ; Character is okay.
  3202.         jmp make_char3
  3203. make_char2:
  3204.         dec si
  3205.         mov al, "%"        ; Put the percent back.
  3206. make_char3:
  3207.         ret
  3208.  
  3209.  
  3210.         db    128 dup (?)    ; Stack.
  3211. stack        label    byte
  3212.  
  3213. lastloc        label    byte        ; End of program.
  3214. code ends
  3215.      end start
  3216. 
  3217.